@dboio/cli 0.11.4 → 0.13.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.
Files changed (48) hide show
  1. package/README.md +126 -3
  2. package/bin/dbo.js +4 -0
  3. package/package.json +1 -1
  4. package/plugins/claude/dbo/.claude-plugin/plugin.json +1 -1
  5. package/plugins/claude/dbo/commands/dbo.md +65 -244
  6. package/plugins/claude/dbo/docs/_audit_required/API/all.md +40 -0
  7. package/plugins/claude/dbo/docs/_audit_required/API/app.md +38 -0
  8. package/plugins/claude/dbo/docs/_audit_required/API/athenticate.md +26 -0
  9. package/plugins/claude/dbo/docs/_audit_required/API/cache.md +29 -0
  10. package/plugins/claude/dbo/docs/_audit_required/API/content.md +14 -0
  11. package/plugins/claude/dbo/docs/_audit_required/API/data_source.md +28 -0
  12. package/plugins/claude/dbo/docs/_audit_required/API/email.md +18 -0
  13. package/plugins/claude/dbo/docs/_audit_required/API/input.md +25 -0
  14. package/plugins/claude/dbo/docs/_audit_required/API/instance.md +28 -0
  15. package/plugins/claude/dbo/docs/_audit_required/API/log.md +8 -0
  16. package/plugins/claude/dbo/docs/_audit_required/API/media.md +12 -0
  17. package/plugins/claude/dbo/docs/_audit_required/API/output_by_entity.md +12 -0
  18. package/plugins/claude/dbo/docs/_audit_required/API/upload.md +7 -0
  19. package/plugins/claude/dbo/docs/_audit_required/dbo-api-syntax.md +1487 -0
  20. package/plugins/claude/dbo/docs/_audit_required/dbo-problems-code.md +111 -0
  21. package/plugins/claude/dbo/docs/_audit_required/dbo-problems-performance.md +109 -0
  22. package/plugins/claude/dbo/docs/_audit_required/dbo-problems-syntax.md +97 -0
  23. package/plugins/claude/dbo/docs/_audit_required/dbo-product-market.md +119 -0
  24. package/plugins/claude/dbo/docs/_audit_required/dbo-white-paper.md +125 -0
  25. package/plugins/claude/dbo/docs/dbo-cheat-sheet.md +323 -0
  26. package/plugins/claude/dbo/docs/dbo-cli-readme.md +2222 -0
  27. package/plugins/claude/dbo/docs/dbo-core-entities.md +878 -0
  28. package/plugins/claude/dbo/docs/dbo-output-customsql.md +677 -0
  29. package/plugins/claude/dbo/docs/dbo-output-query.md +967 -0
  30. package/plugins/claude/dbo/skills/cli/SKILL.md +62 -246
  31. package/src/commands/add.js +366 -62
  32. package/src/commands/build.js +102 -0
  33. package/src/commands/clone.js +602 -139
  34. package/src/commands/diff.js +4 -0
  35. package/src/commands/init.js +16 -2
  36. package/src/commands/input.js +3 -1
  37. package/src/commands/mv.js +12 -4
  38. package/src/commands/push.js +265 -70
  39. package/src/commands/rm.js +16 -3
  40. package/src/commands/run.js +81 -0
  41. package/src/lib/config.js +39 -0
  42. package/src/lib/delta.js +7 -1
  43. package/src/lib/diff.js +24 -2
  44. package/src/lib/filenames.js +120 -41
  45. package/src/lib/ignore.js +6 -0
  46. package/src/lib/input-parser.js +13 -4
  47. package/src/lib/scripts.js +232 -0
  48. package/src/migrations/006-remove-uid-companion-filenames.js +181 -0
@@ -0,0 +1,2222 @@
1
+ # dbo — Command Line Interface for DBO.io
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@dboio/cli.svg)](https://www.npmjs.com/package/@dboio/cli)
4
+ [![npm downloads](https://img.shields.io/npm/dm/@dboio/cli.svg)](https://www.npmjs.com/package/@dboio/cli)
5
+
6
+ A terminal-based CLI for interacting with the [DBO.io](https://dbo.io) framework. Replaces raw curl commands with a clean, subcommand-driven interface for CRUD operations, querying, content deployment, media management, and more.
7
+
8
+ **Available on npm:** [@dboio/cli](https://www.npmjs.com/package/@dboio/cli)
9
+
10
+ ## Installation
11
+
12
+ ### From npm (recommended)
13
+
14
+ ```bash
15
+ npm install -g @dboio/cli
16
+ ```
17
+
18
+ This installs the `dbo` command globally on your system.
19
+
20
+ ### From the repository (local development)
21
+
22
+ ```bash
23
+ cd tools/cli
24
+ npm install
25
+ npm link
26
+ ```
27
+
28
+ ### Without installing (npx)
29
+
30
+ ```bash
31
+ npx @dboio/cli <command>
32
+ ```
33
+
34
+ > **Shorthand:** You can use `dbo i` as a shortcut for `dbo install` (similar to `npm i`).
35
+
36
+ ### Requirements
37
+
38
+ - **Node.js 18+** (uses native `fetch` and `FormData`)
39
+ - A DBO.io instance to connect to
40
+
41
+ ## Claude Code Integration
42
+
43
+ The dbo CLI can be used as a `/dbo` slash command inside Claude Code sessions.
44
+
45
+ ### Install Claude Code commands
46
+
47
+ ```bash
48
+ # Install the /dbo command into your project's .claude/commands/
49
+ dbo install claudecommands
50
+
51
+ # Install globally to ~/.claude/commands/ (shared across projects)
52
+ dbo install claudecommands --global
53
+
54
+ # Or install Claude Code CLI + commands together
55
+ dbo install claudecode
56
+ ```
57
+
58
+ Once installed, use `/dbo` in Claude Code:
59
+ ```
60
+ /dbo pull albain3dwkofbhnd1qtd1q
61
+ /dbo output -e user --maxrows 5
62
+ /dbo push assets/css/
63
+ ```
64
+
65
+ The plugin source lives in `plugins/claude/dbo/` at the repository root. Installed copies in `.claude/plugins/` are gitignored and managed by `dbo install`. Each plugin's installation scope (project or global) is stored per-plugin in `.dbo/config.local.json`.
66
+
67
+ ---
68
+
69
+ ## Upgrading
70
+
71
+ The `dbo install` command handles both fresh installs and upgrades. If a component is already installed, it will prompt you to upgrade to the latest version.
72
+
73
+ ```bash
74
+ # Upgrade CLI to latest version
75
+ dbo install dbo@latest
76
+
77
+ # Install/upgrade to a specific version
78
+ dbo install dbo@0.4.1
79
+
80
+ # Upgrade from local source
81
+ dbo install /path/to/local/cli/src
82
+
83
+ # Upgrade Claude Code commands (prompts if already installed)
84
+ dbo install plugins
85
+
86
+ # Upgrade a specific Claude command
87
+ dbo install --claudecommand dbo
88
+
89
+ # Check your version
90
+ dbo --version
91
+ ```
92
+
93
+ ---
94
+
95
+ ## Quick Start
96
+
97
+ ```bash
98
+ # 1. Initialize configuration for the current directory
99
+ dbo init --domain my-domain.com
100
+
101
+ # 1b. Combined with cloning an app to local project bin
102
+ dbo init --domain my-domain.com --app myapp --clone
103
+
104
+ # 2. Authenticate
105
+ dbo login
106
+
107
+ # 3. Check your session
108
+ dbo status
109
+
110
+ # 4. Query some data
111
+ dbo output -e user --template json_indented --maxrows 5
112
+
113
+ # 5. Deploy a CSS file
114
+ dbo content deploy albain3dwkofbhnd1qtd1q assets/css/colors.css
115
+ ```
116
+
117
+ ---
118
+
119
+ ## Project Directory Structure
120
+
121
+ When you run `dbo init --scaffold` or `dbo clone`, the following standard directories are created in your project root:
122
+
123
+ ```
124
+ my-project/
125
+ ├── .dbo/ # Config, synchronization and session info for dbo cli commands
126
+ ├── .claude/ # Claude Code plugin config (commands, specs, plans, skills)
127
+ ├── lib/ # All DBO server-managed assets
128
+ │ ├── bins/ # Assets (contents, outputs, images, HTML, CSS)
129
+ │ │ └── app/ # Default application bin
130
+ │ ├── automation/ # Automation entity records
131
+ │ ├── app_version/ # App version entity records
132
+ │ ├── entity/ # Entity definitions
133
+ │ ├── entity_column/ # Column definitions
134
+ │ ├── entity_column_value/ # Column value definitions
135
+ │ ├── extension/ # Extension entity records (organized by descriptor type)
136
+ │ │ ├── widget/
137
+ │ │ ├── documentation/
138
+ │ │ └── _unsupported/
139
+ │ ├── integration/ # Integration entity records
140
+ │ ├── security/ # Security policy records
141
+ │ ├── security_column/ # Column-level security records
142
+ │ ├── data_source/ # (created when data sources exist)
143
+ │ ├── group/ # (created when groups exist)
144
+ │ ├── site/ # (created when sites exist)
145
+ │ └── redirect/ # (created when redirects exist)
146
+ ├── src/ # Your actual source code (sass, typescript, etc.)
147
+ ├── test/ # Project-level tests
148
+ ├── trash/ # Staged soft-deleted files from dbo rm
149
+ ├── docs/ # Project documentation and docs entities
150
+ ├── app.json # Clone of original app JSON with @references
151
+ ├── manifest.json # PWA web app manifest (auto-generated from app metadata)
152
+ ├── .gitignore # Tells Git to ignore files in the repo sync
153
+ ├── .dboignore # Tells dbo cli to ignore files in commands
154
+ ├── package.json # Metadata, scripts, and dependency list
155
+ └── package-lock.json # Records exact versions of dependencies installed
156
+ ```
157
+
158
+ > **Breaking change in 0.11.1**: All server-managed directories (`bins/`, `extension/`, `automation/`, etc.) have moved into a `lib/` subdirectory. Existing projects are migrated **automatically** on the first `dbo` command after upgrade. Also, `tests/` has been renamed to `test/`.
159
+
160
+ ---
161
+
162
+ ## Configuration
163
+
164
+ All configuration is **directory-scoped**. Each project folder maintains its own `.dbo/` directory with its own domain and session. Switch environments by switching directories:
165
+
166
+ ```bash
167
+ ~/projects/my-project/ → .dbo/ → my-domain.com
168
+ ~/projects/my-project-prod/ → .dbo/ → prod.dbo.io
169
+ ```
170
+
171
+ ### `.dbo/` directory contents
172
+
173
+ | File | Purpose | Git |
174
+ |------|---------|-----|
175
+ | `config.json` | Domain, app metadata, placement preferences | Committable (shared) |
176
+ | `config.local.json` | Per-user settings: plugin scopes, `_completedMigrations` (system-managed) | Gitignored (per-user) |
177
+ | `ticketing.local.json` | Stored ticket IDs for submission error recovery | Gitignored (per-user) |
178
+ | `credentials.json` | Username, user ID, UID, name, email (no password) | Gitignored (per-user) |
179
+ | `cookies.txt` | Session cookie (Netscape format) | Gitignored (per-user) |
180
+ | `structure.json` | Bin directory mapping (created by `dbo clone`) | Committable (shared) |
181
+ | `metadata_templates.json` | Column templates per entity/descriptor (auto-generated by `dbo clone`) | Committable (shared) |
182
+ | `synchronize.json` | Pending deletions and sync state (updated by `dbo rm` and `dbo push`) | Committable (shared) |
183
+ | `.app_baseline.json` | Server-state snapshot for delta detection — stores column values at last clone/push so `dbo push` can detect which columns changed locally. Read-only (chmod 444); auto-migrated from legacy root `.app.json`. | Committable (shared) |
184
+ | `scripts.json` | Build/push lifecycle hooks (see [Script Hooks](#script-hooks)) | Committable (shared) |
185
+ | `scripts.local.json` | Per-user hook overrides | Gitignored (per-user) |
186
+
187
+ `dbo init` automatically adds `.dbo/credentials.json`, `.dbo/cookies.txt`, `.dbo/config.local.json`, `.dbo/ticketing.local.json`, and `.dbo/scripts.local.json` to `.gitignore` (creates the file if it doesn't exist).
188
+
189
+ > **Upgrading from pre-0.9.9**: The baseline file `.app.json` in the project root has moved to `.dbo/.app_baseline.json`. Running any `dbo` command will auto-migrate the file. You can also manually remove the `.app.json` entry from your `.gitignore`.
190
+
191
+ > **Upgrading from pre-0.11.0**: `TransactionKeyPreset` now applies only to records that carry a `UID` column (core assets). Data records without a UID are always submitted with `RowID` regardless of the preset. Migration 001 runs automatically on first command after upgrade and logs a one-time notice.
192
+
193
+ #### Automatic migrations
194
+
195
+ When the CLI version is upgraded, one-time migration scripts in `tools/cli/src/migrations/` run automatically on the first command invocation in a project directory. Completed migration IDs are recorded in `.dbo/config.local.json` under `_completedMigrations` (per-user, gitignored) so each developer runs them independently and they never re-fire.
196
+
197
+ To skip migrations for a single command run:
198
+
199
+ ```bash
200
+ dbo push bins/ --no-migrate
201
+ dbo clone --app myapp --no-migrate
202
+ ```
203
+
204
+ Use `dbo status` to see how many pending migrations exist.
205
+
206
+ #### config.json reference
207
+
208
+ ```json
209
+ {
210
+ "domain": "my-domain.com",
211
+ "AppID": 10198,
212
+ "AppUID": "abc123",
213
+ "AppName": "My App",
214
+ "AppShortName": "myapp",
215
+ "cloneSource": "default",
216
+ "ContentPlacement": "bin"
217
+ }
218
+ ```
219
+
220
+ | Key | Values | Description |
221
+ |-----|--------|-------------|
222
+ | `domain` | hostname | DBO.io instance to connect to |
223
+ | `AppID` | number | App ID (set by `dbo clone`, used by `dbo add`/`dbo input`) |
224
+ | `AppUID` | string | App UID |
225
+ | `AppName` | string | App display name |
226
+ | `AppShortName` | string | App short name (used for `dbo clone --app`) |
227
+ | `AppModifyKey` | string | ModifyKey for locked/production apps (set by `dbo clone`, used for submission guards) |
228
+ | `TransactionKeyPreset` | `RowUID` \| `RowID` | Row key type (auto-set to `RowUID` during init/clone) |
229
+ | `TicketSuggestionOutput` | string | Output UID for ticket suggestions (auto-set during init, default `ojaie9t3o0kfvliahnuuda`) |
230
+ | `cloneSource` | `"default"` \| file path \| URL | Where the last `dbo clone` fetched app JSON from. `"default"` = server fetch via `AppShortName`; any other value = the explicit local file path or URL used. Set automatically after each successful clone. |
231
+ | `ContentPlacement` | `bin` \| `path` | Where to place content files during clone (default: `bin`) |
232
+ | `<Entity>FilenameCol` | column name | Filename column for entity-dir records (e.g., `ExtensionFilenameCol`) |
233
+
234
+ **File placement:** All content, media, and output files are placed by BinID into the `lib/bins/` directory structure. Records without a BinID go into `lib/bins/` root. Media always uses BinID — no FullPath option. Bins with `Name=null` (legacy) map directly to `lib/bins/` root.
235
+
236
+ ### Root-level project files
237
+
238
+ #### `app.json`
239
+
240
+ Clone of the original app JSON from the server with entity entries replaced by `@path/to/*.metadata.json` references. Created by `dbo init` (empty `{}`) and populated by `dbo clone`. Committed to git.
241
+
242
+ #### `app.json._domain`
243
+
244
+ The `_domain` field in `app.json` stores the project's reference domain (set during `dbo clone`). This is committed to git and used for domain-change detection when running `dbo init --force` or `dbo clone --domain`. It provides a stable cross-user baseline — all collaborators share the same reference domain.
245
+
246
+ #### `manifest.json`
247
+
248
+ A [PWA web app manifest](https://developer.mozilla.org/en-US/docs/Web/Manifest) auto-generated during scaffolding (`dbo init` or `dbo clone`). Values are derived from `app.json` when available:
249
+
250
+ | Field | Source |
251
+ |-------|--------|
252
+ | `name` | `<AppName> \| <domain>` |
253
+ | `short_name` | `AppShortName` |
254
+ | `description` | `App.Description` |
255
+ | `start_url` / `scope` | `/app/<ShortName>/ui/` |
256
+ | `background_color` | Extracted from the `widget` extension matching the app's `ShortName` (field `String4`), defaults to `#ffffff` |
257
+ | `theme_color` | `#000000` |
258
+
259
+ The file is only created if absent — it is never overwritten by subsequent clones, so local edits (icons, screenshots, display overrides) are preserved. A companion `manifest.metadata.json` is auto-created by `dbo push` if missing, allowing the manifest to be pushed to the server as a content record.
260
+
261
+ ### `.dboignore`
262
+
263
+ A gitignore-style file in the project root that controls which files and directories are excluded from CLI operations. Created automatically by `dbo init` with sensible defaults.
264
+
265
+ **Used by:**
266
+ - `dbo init` — scaffold empty-check (determines if directory is "effectively empty")
267
+ - `dbo add .` — directory scanning (which files/dirs to skip); also checked in single-file mode (`dbo add file.html`)
268
+ - `dbo push` — metadata file discovery: skips matching `.metadata.json` / `_output~*.json` files AND any record whose companion content file (`@reference`) matches an ignore pattern
269
+
270
+ **Bypass:** Use `dbo input -d '...'` to submit expressions for a file that would otherwise be ignored — `dbo input` never does file discovery so `.dboignore` does not apply.
271
+
272
+ **Pattern examples:**
273
+
274
+ ```gitignore
275
+ # Ignore all SQL companion files (output records with CustomSQL)
276
+ **/*.CustomSQL.sql
277
+
278
+ # Ignore a specific record (by metadata file path)
279
+ bins/app/my-draft-page.metadata.json
280
+
281
+ # Ignore an entire directory
282
+ bins/staging/
283
+
284
+ # Ignore all content in bins/ (still push entity-dir records like extension/)
285
+ bins/
286
+ ```
287
+
288
+ **Syntax:** Same as `.gitignore` — glob patterns, `#` comments, blank lines, negation with `!`, directory-only patterns with trailing `/`.
289
+
290
+ **Default patterns:**
291
+
292
+ ```gitignore
293
+ .dbo/ # DBO internal
294
+ *.dboio.json # Export files
295
+ app.json # Clone output
296
+ .git/ # Version control
297
+ .gitignore
298
+ node_modules/ # Node
299
+ package.json
300
+ package-lock.json
301
+ .claude/ # AI / tooling
302
+ .mcp.json
303
+ .DS_Store # Editor / IDE / OS
304
+ Thumbs.db
305
+ Icon\r
306
+ .idea/
307
+ .vscode/
308
+ *.codekit3
309
+ README.md # Repo scaffolding
310
+ SETUP.md
311
+ ```
312
+
313
+ Edit `.dboignore` to add or remove patterns. Committed to git and shared across users.
314
+
315
+ ### Legacy migration
316
+
317
+ If your project uses the older `.domain`, `.username`, `.password`, `.cookies` files, `dbo init` will detect them and offer to migrate automatically.
318
+
319
+ ### Environment variables
320
+
321
+ Environment variables override file-based configuration:
322
+
323
+ - `DBO_DOMAIN` — target domain
324
+ - `DBO_USERNAME` — username
325
+ - `DBO_PASSWORD` — password
326
+
327
+ ---
328
+
329
+ ## Commands
330
+
331
+ ### `dbo init`
332
+
333
+ Initialize DBO CLI configuration for the current directory.
334
+
335
+ ```bash
336
+ dbo init # interactive prompts
337
+ dbo init --domain my-domain.com # non-interactive
338
+ dbo init --domain my-domain.com --username me@co.io # with credentials
339
+ dbo init --force # overwrite existing config
340
+ dbo init --domain my-domain.com --app myapp --clone # init + clone an app
341
+ dbo init --domain my-domain.com -y # skip all prompts
342
+ dbo init --scaffold # scaffold dirs (prompts for domain)
343
+ dbo init --scaffold --yes # scaffold dirs non-interactively
344
+ ```
345
+
346
+ | Flag | Description |
347
+ |------|-------------|
348
+ | `--domain <host>` | DBO instance domain |
349
+ | `--username <user>` | DBO username (stored for login default) |
350
+ | `--force` | Overwrite existing configuration. Triggers a domain-change confirmation prompt when the new domain differs from the project reference domain |
351
+ | `--app <shortName>` | App short name (triggers clone after init). Prompts for password and authenticates automatically before fetching app data from the server |
352
+ | `--clone` | Clone the app after initialization |
353
+ | `-g, --global` | Install Claude commands globally (`~/.claude/commands/`) |
354
+ | `--local` | Install Claude commands to project (`.claude/commands/`) |
355
+ | `--scaffold` | Pre-create standard project directories (`app_version`, `automation`, `bins`, `data_source`, `docs`, `extension`, `group`, `integration`, `site`, `src`, `tests`, `trash`) |
356
+ | `--dboignore` | Create `.dboignore` with default patterns (use with `--force` to overwrite existing) |
357
+ | `-y, --yes` | Skip all interactive prompts (legacy migration, Claude Code setup) |
358
+ | `--non-interactive` | Alias for `--yes` |
359
+
360
+ ---
361
+
362
+ ### `dbo clone`
363
+
364
+ Clone an app from DBO.io to a local project structure. Creates directories, files, metadata, and populates `config.json` and `package.json`.
365
+
366
+ ```bash
367
+ # Clone using config (AppShortName from .dbo/config.json)
368
+ dbo clone
369
+
370
+ # Clone from a local JSON export file
371
+ dbo clone /path/to/app_export.json
372
+
373
+ # Clone from server by app short name
374
+ dbo clone --app myapp
375
+
376
+ # Combined with init
377
+ dbo init --domain my-domain.com --app myapp --clone
378
+
379
+ # Extension descriptor sub-directory handling
380
+ dbo clone -e extension # Clone all extensions (sorted by descriptor type)
381
+ dbo clone -e extension --documentation-only # Clone only documentation extensions
382
+ dbo clone -e extension --documentation-only --force # Reset documentation preferences and re-clone
383
+ dbo clone -e extension --descriptor-types false # Clone extensions flat (no descriptor sorting)
384
+ ```
385
+
386
+ | Flag | Description |
387
+ |------|-------------|
388
+ | `<source>` | Local file path or URL to load app JSON from (optional positional argument) |
389
+ | `--app <name>` | App short name to fetch from server |
390
+ | `-e, --entity <type>` | Only clone a specific entity type (e.g. `output`, `content`, `media`, `extension`) |
391
+ | `--documentation-only` | When used with `-e extension`, clone only documentation extensions |
392
+ | `--descriptor-types <bool>` | Sort extensions into descriptor sub-directories (default: `true`). Set to `false` to use flat `extension/` layout |
393
+ | `--domain <host>` | Override domain. Triggers a domain-change confirmation prompt when it differs from the project reference domain |
394
+ | `--force` | Skip source mismatch confirmation and change detection; re-processes all files |
395
+ | `-y, --yes` | Auto-accept all prompts (also skips source mismatch confirmation) |
396
+ | `-v, --verbose` | Show HTTP request details |
397
+
398
+ #### Domain change detection
399
+
400
+ When cloning with a different domain than the project's reference domain (`app.json._domain` or `config.json.domain`), the CLI warns before proceeding. When `TransactionKeyPreset=RowID`, this escalates to a critical error because numeric IDs are not unique across domains — pushing to the wrong domain can corrupt records. In non-interactive mode (`-y`), RowUID domain changes proceed with a warning, but RowID domain changes throw a hard error.
401
+
402
+ The project's reference domain is stored in `app.json._domain` (committed to git) during clone, giving the CLI a stable cross-user baseline.
403
+
404
+ #### What clone does
405
+
406
+ 1. **Loads app JSON** — from a local file, server API, or interactive prompt. A spinner shows progress while fetching from the server (responses can be slow as the JSON is assembled on demand)
407
+ 2. **Updates `.dbo/config.json`** — saves `AppID`, `AppUID`, `AppName`, `AppShortName`, `AppModifyKey` (if the app is locked), and `cloneSource` (the source used for this clone)
408
+ 3. **Updates `package.json`** — populates `name`, `productName`, `description`, `homepage`, and `deploy` script
409
+ 4. **Creates directories** — processes `children.bin` to build the directory hierarchy based on `ParentBinID` relationships
410
+ 5. **Saves `.dbo/structure.json`** — maps BinIDs to directory paths for file placement
411
+ 6. **Writes content files** — decodes base64 content, creates `*.metadata.json` + content files in the correct bin directory. When a record's `Extension` field is empty, prompts you to choose from `css`, `js`, `html`, `xml`, `txt`, `md`, `cs`, `json`, `sql` (or skip to keep no extension). The chosen extension is saved back into the `metadata.json` `Extension` field
412
+ 7. **Downloads media files** — fetches binary files (images, CSS, fonts) from the server using a fallback chain: `FullPath` directly (`/media/{app}/{path}`) → `/dir/` route → `/api/media/{uid}`, and saves with metadata. Errors are logged to `.dbo/errors.log`
413
+ 8. **Processes entity-dir records** — entities matching project directories (`extension`, `app_version`, `data_source`, `site`, `group`, `integration`, `automation`) are saved as `.metadata.json` files in their corresponding directory (e.g., `extension/`, `data_source/`)
414
+ 9. **Processes other entities** — remaining entities with a `BinID` are placed in the corresponding bin directory
415
+ 10. **Saves `app.json`** — clone of the original JSON with processed entries replaced by `@path/to/*.metadata.json` references
416
+ 11. **Orphan cleanup** — any local `.metadata.json` files whose UID is absent from the server response are automatically moved to `trash/` along with their companion content and media files. This prevents stale records (deleted server-side) from causing false positives in `dbo push`. Skipped during `--entity-filter` clones
417
+
418
+ #### Clone source tracking
419
+
420
+ After every successful clone, the source is persisted as `cloneSource` in `.dbo/config.json`:
421
+
422
+ - `"default"` — app JSON was fetched from the server using `AppShortName` (the normal flow)
423
+ - A file path or URL — set when an explicit `<source>` argument was provided (e.g. `dbo clone /path/to/export.json`)
424
+
425
+ On subsequent clones, if you provide an explicit source that **differs** from the stored `cloneSource`, the CLI warns and asks for confirmation before proceeding:
426
+
427
+ ```
428
+ ⚠ This project was previously cloned from: default
429
+ Requested source: /path/to/export.json
430
+ ? Clone from the new source anyway? This will update the stored clone source. (y/N)
431
+ ```
432
+
433
+ Use `--force` or `-y` to skip the prompt and override without being asked.
434
+
435
+ If the initial clone attempt fails (network error, file not found, empty response), the CLI prompts for a fallback source to retry with instead of aborting:
436
+
437
+ ```
438
+ ⚠ Source did not return expected results: No app found with ShortName "myapp"
439
+ ? Enter another local file path or URL to retry (or leave empty to abort):
440
+ ```
441
+
442
+ #### Change detection on re-clone
443
+
444
+ When cloning an app that was already cloned locally, the CLI detects existing files and compares modification times against the server's `_LastUpdated`. You'll be prompted to overwrite, compare differences, or skip — same as `dbo pull`. Use `-y` to auto-accept all changes.
445
+
446
+ #### Collision detection
447
+
448
+ When multiple records would create files at the same path (e.g., a `content` record and a `media` record both named `colors.css`), the CLI detects the collision before writing any files and prompts you to choose which record to keep:
449
+
450
+ ```
451
+ ⚠ Collision: 2 records want to create "bins/app/colors.css"
452
+ ? Which record should create this file?
453
+ ❯ [content] colors (UID: abc123)
454
+ [media] colors.css (UID: def456)
455
+ ```
456
+
457
+ The rejected record is automatically staged for deletion in `.dbo/synchronize.json`. Run `dbo push` to delete it from the server.
458
+
459
+ In non-interactive mode (`-y`), the first record is kept and others are auto-staged for deletion.
460
+
461
+ #### Stale media cleanup
462
+
463
+ During media downloads, files returning 404 (no longer exist on the server) are collected as "stale records". After all downloads complete, you'll be prompted to stage them for deletion:
464
+
465
+ ```
466
+ Found 3 stale media record(s) (404 - files no longer exist on server)
467
+ ? Stage these 3 stale media records for deletion? (y/N)
468
+ ```
469
+
470
+ This helps keep your app clean by removing database records for media files that have been deleted from the server.
471
+
472
+ In non-interactive mode (`-y`), stale cleanup is skipped (conservative default).
473
+
474
+ #### Path resolution
475
+
476
+ When a content record has both `Path` and `BinID`, the CLI prompts:
477
+ ```
478
+ Where do you want me to place filename.ext?
479
+ 1. Into the Path of /path/from/path/column
480
+ 2. Into the BinID of 12345 (mapped BinName → bin/directory)
481
+ ```
482
+
483
+ #### Entity directory processing
484
+
485
+ Entity types that correspond to project directories (`extension`, `app_version`, `data_source`, `site`, `group`, `integration`, `automation`) are processed into their named directories without requiring a `BinID`:
486
+
487
+ | Entity Key | Directory |
488
+ |------------|-----------|
489
+ | `extension` | `extension/<Descriptor>/` (see below) |
490
+ | `app_version` | `app_version/` |
491
+ | `data_source` | `data_source/` |
492
+ | `site` | `site/` |
493
+ | `group` | `group/` |
494
+ | `integration` | `integration/` |
495
+ | `automation` | `automation/` |
496
+
497
+ For each entity type, the CLI prompts to choose which column becomes the filename (defaults to `Name`, fallback `UID`). The choice is saved per entity type in `config.json` (e.g., `ExtensionFilenameCol`).
498
+
499
+ If any columns contain base64-encoded content, the CLI prompts to extract them as companion files. Extracted columns produce files named `<name>.<Column>.<ext>` alongside the metadata, with `@reference` entries in the metadata and a `_contentColumns` array.
500
+
501
+ Use `-y` to skip prompts (uses `Name` column, no content extraction).
502
+
503
+ #### Extension descriptor sub-directories
504
+
505
+ Extension records are organized into sub-directories under `extension/` based on their `Descriptor` column value. A special extension type called `descriptor_definition` (itself an extension with `Descriptor === "descriptor_definition"`) provides the mapping from descriptor key (`String1`) to display/directory name (`Name`).
506
+
507
+ During clone, the CLI:
508
+
509
+ 1. **Pre-scans** all extension records for `descriptor_definition` entries and builds a `String1 → Name` mapping
510
+ 2. **Creates sub-directories** under `extension/` for each mapped descriptor (e.g., `extension/Documentation/`, `extension/Includes/`)
511
+ 3. **Always creates** `extension/_unsupported/` — extensions with an unmapped or null `Descriptor` are placed here
512
+ 4. **Prompts per descriptor** — filename column and content extraction prompts fire once per unique `Descriptor` value (not once for all extensions)
513
+ 5. **Persists the mapping** in `.dbo/structure.json` under `descriptorMapping`
514
+
515
+ **Config keys** (saved per descriptor in `config.json`):
516
+
517
+ | Key | Example | Purpose |
518
+ |-----|---------|---------|
519
+ | `Extension_<descriptor>_FilenameCol` | `Extension_documentation_FilenameCol` | Filename column for that descriptor type |
520
+ | `Extension_<descriptor>_ContentExtractions` | `Extension_documentation_ContentExtractions` | Content extraction preferences per column |
521
+ | `ExtensionDocumentationMDPlacement` | `"inline"` or `"root"` | Where to place documentation MD files |
522
+
523
+ **Documentation alternate placement**: When extracting MD content from `documentation` descriptor extensions, the CLI offers a choice:
524
+
525
+ - **Root placement** (`/docs/<filename>.md`) — recommended for easy access; creates `@/docs/<filename>.md` references in metadata
526
+ - **Inline placement** (`extension/Documentation/<filename>.md`) — keeps files alongside metadata
527
+
528
+ Root-placed files use absolute-from-root `@/` references (e.g., `@/docs/my-doc.md`) so `dbo push` can locate them regardless of where the metadata lives.
529
+
530
+ **Entity filter support**:
531
+
532
+ ```bash
533
+ dbo clone -e extension --documentation-only # Clone only documentation extensions
534
+ dbo clone -e extension --documentation-only --force # Reset documentation preferences and re-clone
535
+ dbo clone -e extension # Clone all extensions (all descriptor types)
536
+ dbo clone -e extension --descriptor-types false # Flat layout (no descriptor sorting)
537
+ ```
538
+
539
+ **`dbo add` auto-inference**: Running `dbo add docs/my-doc.md` when `ExtensionDocumentationMDPlacement` is `"root"` auto-creates a companion `.metadata.json` in `extension/documentation/` with the correct `@/` reference.
540
+
541
+ #### Output structure
542
+
543
+ ```
544
+ project/
545
+ .dbo/
546
+ config.json # Updated with app metadata
547
+ structure.json # Bin directory mapping
548
+ .gitignore # credentials.json + cookies.txt added
549
+ package.json # Updated with app info + deploy script
550
+ app.json # Clone of original with @references
551
+ bins/ # ← root for all bin-placed files
552
+ app/ # ← directory from children.bin
553
+ thomas-scratch.md
554
+ thomas-scratch.metadata.json
555
+ CurrentTicketID.cs
556
+ CurrentTicketID.metadata.json
557
+ ticket_test/ # ← another bin directory
558
+ ...
559
+ extension/ # ← extension records organized by descriptor
560
+ Documentation/ # ← descriptor sub-directory (from descriptor_definition)
561
+ MyDoc.uid1.metadata.json
562
+ MyDoc.uid1.String10.md # ← extracted content column
563
+ Includes/
564
+ Header.uid2.metadata.json
565
+ _unsupported/ # ← always created (unmapped/null descriptors)
566
+ docs/ # ← root-placed documentation MD files (optional)
567
+ MyDoc.md
568
+ data_source/
569
+ MySQL-Primary.metadata.json
570
+ site/
571
+ MainSite.metadata.json
572
+ # Media files placed by BinID into bins/ (alongside content)
573
+ ```
574
+
575
+ #### Understanding the `lib/bins/` directory structure
576
+
577
+ The `lib/bins/` directory is the default location for all bin-placed content files during clone. It organizes files according to your app's bin hierarchy from DBO.io.
578
+
579
+ **Directory Organization:**
580
+
581
+ - **`lib/bins/`** — Root directory for all bin-placed files (local organizational directory only)
582
+ - **`lib/bins/app/`** — Special subdirectory for the main app bin (typically the default bin)
583
+ - **`lib/bins/custom_name/`** — Custom bin directories (e.g., `tpl/`, `ticket_test/`, etc.)
584
+
585
+ **Important: The `lib/bins/app/` special case**
586
+
587
+ The `app/` subdirectory under `lib/bins/` is treated specially:
588
+
589
+ 1. **It's organizational only** — The `lib/bins/app/` prefix exists only for local file organization and is **not part of the server-side path**.
590
+
591
+ 2. **Path normalization** — When comparing paths (during `dbo push`), the CLI automatically strips both `lib/bins/` and `app/` from paths:
592
+ ```
593
+ Local file: lib/bins/app/assets/css/operator.css
594
+ Server Path: assets/css/operator.css
595
+ → These are considered the same path ✓
596
+ ```
597
+
598
+ 3. **Custom bins are preserved** — Other subdirectories like `lib/bins/tpl/` or `lib/bins/ticket_test/` represent actual bin hierarchies and their names are meaningful:
599
+ ```
600
+ Local file: lib/bins/tpl/header.html
601
+ Server Path: tpl/header.html
602
+ → The 'tpl/' directory is preserved ✓
603
+ ```
604
+
605
+ **Why this matters:**
606
+
607
+ - When you `dbo push` files from `lib/bins/app/`, the CLI knows these paths should match the root-level paths in your metadata
608
+ - If your metadata `Path` column contains `assets/css/colors.css`, it will correctly match files in `lib/bins/app/assets/css/colors.css`
609
+ - Custom bin directories like `lib/bins/tpl/` serve from the `tpl/` directive and maintain their path structure
610
+
611
+ **Leading slash handling:**
612
+
613
+ The CLI handles leading `/` in metadata paths flexibly:
614
+ - `Path: assets/css/file.css` matches `lib/bins/app/assets/css/file.css` ✓
615
+ - `Path: /assets/css/file.css` also matches `lib/bins/app/assets/css/file.css` ✓
616
+ - `Path: /assets/css/file.css` matches `lib/bins/assets/css/file.css` ✓
617
+
618
+ This ensures compatibility with various path formats from the server while maintaining correct local file organization.
619
+
620
+ #### Media file serving (API)
621
+
622
+ The DBO.io server provides three routes for serving media files:
623
+
624
+ | Route | Example | Description |
625
+ |-------|---------|-------------|
626
+ | `/media/{app}/{path}` | `/media/todoes/App/assets/fonts/file.ttf` | Legacy FullPath — the value stored in the media record's `FullPath` column |
627
+ | `/dir/{app}/{bins}/{file}` | `/dir/todoes/App/assets/fonts/file.ttf` | Modern BinID-based route — parses `appShortName/binHierarchy/filename` |
628
+ | `/api/media/{uid}` | `/api/media/ujrOQPCdUEamNJdAjUQdYA` | UID-based endpoint — looks up media by unique identifier |
629
+
630
+ During `dbo clone`, the CLI downloads media using a **fallback chain**:
631
+
632
+ 1. **FullPath** (`/media/...`) — uses the record's `FullPath` column directly
633
+ 2. **`/dir/` route** — strips the `/media/` prefix from FullPath and uses the `/dir/` route
634
+ 3. **`/api/media/{uid}`** — UID-based endpoint as last resort (when no FullPath exists)
635
+
636
+ If all attempts fail, the error is logged to `.dbo/errors.log` (JSONL format) with the record's UID, filename, FullPath, and error details.
637
+
638
+ #### Output hierarchy format
639
+
640
+ Each root output record produces a **single compound JSON file** containing all child entities (columns, joins, filters) embedded inline:
641
+
642
+ ```
643
+ bins/app/
644
+ _output~Sales~abc123.json ← root output with inline children
645
+ _output~Sales~abc123.column~col1.CustomSQL.sql ← companion SQL file
646
+ ```
647
+
648
+ The root JSON structure:
649
+ ```json
650
+ {
651
+ "_entity": "output",
652
+ "UID": "abc123",
653
+ "Name": "Sales",
654
+ "children": {
655
+ "column": [
656
+ { "_entity": "output_value", "UID": "col1", "Title": "Amount", "children": { "column": [], "join": [], "filter": [] } }
657
+ ],
658
+ "join": [],
659
+ "filter": [
660
+ { "_entity": "output_value_filter", "UID": "f1", "ShortName": "Active", "children": { "column": [], "join": [], "filter": [] } }
661
+ ]
662
+ }
663
+ }
664
+ ```
665
+
666
+ Key points:
667
+ - All three child keys (`column`, `join`, `filter`) are always present (empty arrays when unused)
668
+ - Each child retains `_entity` set to its physical table name for push routing
669
+ - Children nest recursively following FK relationships (e.g. a column can have filters)
670
+ - `CustomSQL` content is extracted to companion `.sql` files per extraction rules
671
+ - Re-cloning moves orphaned old-format child `.json` files to `/trash`
672
+
673
+ #### Metadata Templates
674
+
675
+ During `dbo clone`, the CLI auto-generates `.dbo/metadata_templates.json` — a file that records which columns each entity/descriptor uses. This file is seeded from the first cloned record of each type and can be manually edited afterwards.
676
+
677
+ **File format:**
678
+
679
+ ```json
680
+ {
681
+ "site": ["AppID", "Name", "ShortName", "Active"],
682
+ "extension": {
683
+ "documentation": ["AppID", "Name", "Descriptor=documentation", "String10=@reference"],
684
+ "control": ["AppID", "Name", "ShortName", "Active"]
685
+ }
686
+ }
687
+ ```
688
+
689
+ **Column syntax:**
690
+
691
+ | Syntax | Meaning |
692
+ |--------|---------|
693
+ | `Name` | Plain column — populated from filename or left empty |
694
+ | `Descriptor=documentation` | Literal value — always set to `documentation` |
695
+ | `String10=@reference` | Content reference — links to the file being added |
696
+
697
+ `dbo add` uses these templates to auto-detect the entity type from a file's directory placement and generate metadata without prompting. For example, `dbo add extension/include/nav.html` resolves to entity `extension` / descriptor `include` and applies the matching template.
698
+
699
+ ---
700
+
701
+ ### `dbo login`
702
+
703
+ Authenticate with a DBO.io instance and store the session cookie.
704
+
705
+ After successful authentication, the CLI automatically fetches and stores the current user's ID, UID, name, and email in `.dbo/credentials.json`. The ID and UID are used for automatic retry when server submissions require user identity (see [Automatic error recovery](#automatic-error-recovery)). The name and email are used to populate `package.json` author fields during `dbo clone`.
706
+
707
+ > **Note:** User info is currently retrieved via a separate API call after login. This is a temporary workaround — the authentication endpoint should include user info in its response directly.
708
+
709
+ ```bash
710
+ dbo login # uses stored credentials
711
+ dbo login -u user@example.com -p myPassword # explicit credentials
712
+ dbo login -e user@example.com # authenticate by email
713
+ dbo login --phone +15551234567 -p myPassword # authenticate by phone
714
+ dbo login --passkey abc123def # authenticate with passkey
715
+ ```
716
+
717
+ | Flag | Description |
718
+ |------|-------------|
719
+ | `-u, --username <value>` | Username identity |
720
+ | `-e, --email <value>` | Email identity |
721
+ | `--phone <value>` | Phone number identity |
722
+ | `-p, --password <value>` | Password credential |
723
+ | `--passkey <value>` | Passkey credential (rotating API key) |
724
+ | `--domain <host>` | Override domain for this request |
725
+
726
+ ---
727
+
728
+ ### `dbo logout`
729
+
730
+ Log out and clear the local session cookie.
731
+
732
+ ```bash
733
+ dbo logout
734
+ ```
735
+
736
+ ---
737
+
738
+ ### `dbo status`
739
+
740
+ Show current configuration, domain, and session status.
741
+
742
+ ```bash
743
+ dbo status
744
+ ```
745
+
746
+ Output:
747
+ ```
748
+ Initialized: Yes (.dbo/)
749
+ Domain: my-domain.com
750
+ Username: user@example.com
751
+ User ID: 10296
752
+ Directory: /Users/me/projects/operator
753
+ Session: Active (expires: 2026-03-15T10:30:00.000Z)
754
+ Cookies: /Users/me/projects/operator/.dbo/cookies.txt
755
+
756
+ Claude Code Plugins:
757
+ dbo: ✓ global (~/.claude/commands/dbo.md)
758
+ ```
759
+
760
+ User ID is populated by `dbo login`. If it shows "(not set)", run `dbo login` to fetch it.
761
+
762
+ Plugin scopes (project or global) are displayed when plugins have been installed. Scopes are stored in `.dbo/config.local.json`.
763
+
764
+ ---
765
+
766
+ ### `dbo input`
767
+
768
+ Submit CRUD operations (add, edit, delete records) to DBO.io. This is the core data manipulation command.
769
+
770
+ ```bash
771
+ # Add a record
772
+ dbo input -d 'RowID:add1;column:user.FirstName=John' -d 'RowID:add1;column:user.LastName=Doe'
773
+
774
+ # Edit a record by UID
775
+ dbo input -d 'RowUID:albain3dwkofbhnd1qtd1q;column:content.Content@assets/css/colors.css'
776
+
777
+ # Delete a record
778
+ dbo input -d 'RowID:del10062;entity:user=true'
779
+
780
+ # Multiple operations in one call
781
+ dbo input -d 'RowID:add1;column:user.LastName=Doe&RowUID:abc;column:content.Content@file.css'
782
+
783
+ # With file upload (multipart)
784
+ dbo input -d 'RowID:add1;column:media.BinID=12345' -f file=@path/to/image.jpg
785
+
786
+ # Validation only (no commit)
787
+ dbo input -d 'RowID:add1;column:user.FirstName=John' --confirm false
788
+
789
+ # With ticket ID override
790
+ dbo input -d 'RowID:add1;column:content.Name=test' --ticket abc123
791
+
792
+ # See the HTTP request being made
793
+ dbo input -d 'RowUID:abc;column:content.Content@file.css' -v
794
+ ```
795
+
796
+ | Flag | Description |
797
+ |------|-------------|
798
+ | `-d, --data <expr>` | DBO input expression (repeatable) |
799
+ | `-f, --file <field=@path>` | File attachment for multipart upload (repeatable) |
800
+ | `-C, --confirm <true\|false>` | Commit changes (default: `true`). Use `false` for validation only |
801
+ | `--ticket <id>` | Override ticket ID (`_OverrideTicketID`) |
802
+ | `--modify-key <key>` | Provide ModifyKey directly (skips interactive prompt) |
803
+ | `--row-key <type>` | Row key type (`RowUID` or `RowID`) — no-op for `-d` passthrough, available for consistency |
804
+ | `--login` | Auto-login user created by this submission |
805
+ | `--transactional` | Use transactional processing |
806
+ | `--json` | Output raw JSON response |
807
+ | `-v, --verbose` | Show HTTP request details |
808
+ | `--domain <host>` | Override domain |
809
+
810
+ #### Input expression syntax
811
+
812
+ ```
813
+ RowID:identifier;column:entity.ColumnName=value # direct value
814
+ RowUID:identifier;column:entity.ColumnName@filepath # value from file
815
+ RowID:delIdentifier;entity:entityName=true # delete
816
+ ```
817
+
818
+ The `@filepath` syntax reads the file contents and uses them as the column value. This is how CSS, JS, HTML, and other text content is deployed to DBO.
819
+
820
+ ---
821
+
822
+ ### `dbo output`
823
+
824
+ Query data from DBO.io outputs or entities.
825
+
826
+ ```bash
827
+ # Custom output by UID
828
+ dbo output qfkyyp2vxeaggdeo7dwbig
829
+
830
+ # Entity query
831
+ dbo output -e user --template json_indented
832
+
833
+ # Single record
834
+ dbo output -e user --row 10296
835
+
836
+ # With filtering and sorting
837
+ dbo output -e user --filter 'FirstName=John' --sort 'LastName:asc' --template json_indented
838
+
839
+ # Contains filter
840
+ dbo output -e content --filter 'Name:contains=color' --template json_indented
841
+
842
+ # Pagination
843
+ dbo output -e user --page 2 --rows-per-page 25
844
+
845
+ # Save results to local files (interactive)
846
+ dbo output -e content --filter 'AppID=10100' --save
847
+
848
+ # Save results to local files (non-interactive / scripting)
849
+ dbo output -e content --save-filename Name --save-path Path --save-content Content --save-extension Extension
850
+
851
+ # Entity metadata
852
+ dbo output -e user --meta
853
+
854
+ # Debug SQL
855
+ dbo output myOutputUID --debug-sql
856
+ ```
857
+
858
+ | Flag | Description |
859
+ |------|-------------|
860
+ | `<uid>` | Output UID (positional argument) |
861
+ | `-e, --entity <uid>` | Query by entity UID |
862
+ | `--row <id>` | Specific row ID |
863
+ | `--filter <expr>` | Filter expression (repeatable) |
864
+ | `--template <value>` | Output template: `json_raw` (default), `json_indented`, `json`, `html`, `csv`, `xml`, `txt`, `pdf`, or a content UID for custom templates |
865
+ | `--sort <expr>` | Sort expression (repeatable), e.g., `LastName:asc` |
866
+ | `--search <expr>` | Full-text search |
867
+ | `--page <n>` | Page number |
868
+ | `--rows-per-page <n>` | Rows per page |
869
+ | `--maxrows <n>` | Maximum rows |
870
+ | `--rows <range>` | Row range, e.g., `1-10` |
871
+ | `--limit <n>` | Maximum rows to return (preferred over `--maxrows`) |
872
+ | `--rowcount <bool>` | Include row count: `true` (default) or `false` for performance |
873
+ | `--display <expr>` | Show/hide template tags (repeatable), e.g., `sidebar=hide` |
874
+ | `--format-values` | Enable value formatting with `--template json_raw` |
875
+ | `--empty-response-code <code>` | HTTP status code when output returns no results |
876
+ | `--fallback-content <expr>` | Fallback content UID for error codes, e.g., `404=contentUID` |
877
+ | `--escape-html <bool>` | Control HTML escaping: `true` or `false` |
878
+ | `--mime <type>` | Override MIME/content type |
879
+ | `--strict` | Strict error mode |
880
+ | `--confirm` | Confirmation flag |
881
+ | `--include <expr>` | Include token |
882
+ | `--no-transaction` | Disable transaction wrapping |
883
+ | `--skip <phase>` | Skip execution phases (repeatable, admin-only) |
884
+ | `--profile` | Enable MiniProfiler output |
885
+ | `--debug` | Include debug info |
886
+ | `--debug-sql` | Include SQL debug info |
887
+ | `--debug-verbose` | Verbose debug output |
888
+ | `--debug-analysis` | Analysis debug output |
889
+ | `--meta` | Use meta output endpoint |
890
+ | `--meta-column <uid>` | Column metadata |
891
+ | `--save` | Interactive save-to-disk mode |
892
+ | `--save-filename <col>` | Column for filenames (non-interactive) |
893
+ | `--save-path <col>` | Column for file path (non-interactive) |
894
+ | `--save-content <col>` | Column for file content (non-interactive) |
895
+ | `--save-extension <col>` | Column or literal extension (non-interactive) |
896
+ | `--json` | Output raw JSON |
897
+ | `-v, --verbose` | Show HTTP request details |
898
+
899
+ #### Save to Disk (`--save`)
900
+
901
+ The save-to-disk feature fetches data and persists records as local files. It uses an interactive flow with arrow-key selection prompts:
902
+
903
+ 1. **Filename column** — which column value becomes the filename (default: `Name` or `UID`)
904
+ 2. **Path column** — which column contains the directory path (builds local directories)
905
+ 3. **Content column(s)** — which column(s) to save as file content (skip for metadata only)
906
+ 4. **Extension** — use an entity column or specify manually
907
+
908
+ Each record produces:
909
+ - A content file: `[filename]~[uid].[extension]` (e.g., `colors~abc123.css`)
910
+ - A metadata file: `[filename]~[uid].metadata.json` (all column values)
911
+
912
+ ### Tilde UID Convention
913
+
914
+ Every local file whose server record has a known UID embeds that UID in the filename, separated by a tilde (`~`):
915
+
916
+ - Content: `<basename>~<uid>.<ext>` / `<basename>~<uid>.metadata.json`
917
+ - Media: `<basename>~<uid>.<ext>` / `<basename>~<uid>.<ext>.metadata.json`
918
+ - Entity-dir: `<name>~<uid>.metadata.json`
919
+
920
+ Exception: if the chosen filename column value *is* the UID itself, the tilde suffix is omitted: `<uid>.<ext>`.
921
+
922
+ When pushing, the `~<uid>` portion is automatically stripped from filenames sent to the server (e.g., `logo~def456.png` is uploaded as `logo.png`).
923
+
924
+ If the path column contains a filename (e.g., `assets/js/main.js`), the CLI detects it and asks if you want to use it.
925
+
926
+ ---
927
+
928
+ ### `dbo content`
929
+
930
+ Get, deploy, or pull content from DBO.io.
931
+
932
+ ```bash
933
+ # Get content by UID
934
+ dbo content ykqucv0eb0ggjqgcncj6dq
935
+
936
+ # Save content to a local file
937
+ dbo content ykqucv0eb0ggjqgcncj6dq -o local/file.html
938
+
939
+ # Get as plain text (disable minification)
940
+ dbo content ykqucv0eb0ggjqgcncj6dq --template txt --no-minify
941
+ ```
942
+
943
+ | Flag | Description |
944
+ |------|-------------|
945
+ | `<uid>` | Content UID |
946
+ | `-o, --output <path>` | Save to local file |
947
+ | `--template <value>` | Output template (e.g., `json_raw`, `html`, `txt`, or a content UID) |
948
+ | `--no-minify` | Disable minification |
949
+ | `--json` | Output raw JSON |
950
+
951
+ #### `dbo content deploy`
952
+
953
+ Deploy a local file's contents to a DBO content record.
954
+
955
+ ```bash
956
+ dbo content deploy albain3dwkofbhnd1qtd1q assets/css/colors.css
957
+ dbo content deploy rncjivlghu65bmkbjnxynq assets/js/app.js
958
+ dbo content deploy abc123 docs/readme.md --ticket myTicket
959
+ dbo content deploy abc123 test.html --confirm false # validate only
960
+ dbo content deploy abc123 image.png --multipart # binary file upload
961
+ ```
962
+
963
+ This is a shorthand for:
964
+ ```bash
965
+ dbo input -d 'RowUID:albain3dwkofbhnd1qtd1q;column:content.Content@assets/css/colors.css'
966
+ ```
967
+
968
+ | Flag | Description |
969
+ |------|-------------|
970
+ | `<uid>` | Content UID (RowUID) |
971
+ | `<filepath>` | Local file path |
972
+ | `-C, --confirm <true\|false>` | Commit (default: `true`) |
973
+ | `--ticket <id>` | Override ticket ID |
974
+ | `--modify-key <key>` | Provide ModifyKey directly (skips interactive prompt) |
975
+ | `--multipart` | Use multipart/form-data upload (for binary files) |
976
+ | `--row-key <type>` | Override row key type for this invocation (`RowUID` or `RowID`) |
977
+
978
+ #### `dbo content pull`
979
+
980
+ Pull content records from DBO to local files. Uses the content entity's well-known columns (`Name`, `Path`, `Content`, `Extension`) automatically — no interactive prompts.
981
+
982
+ ```bash
983
+ # Pull a single content record
984
+ dbo content pull ykqucv0eb0ggjqgcncj6dq
985
+
986
+ # Pull all content for an app
987
+ dbo content pull --filter 'AppID=10100'
988
+
989
+ # Pull with row limit
990
+ dbo content pull --filter 'AppID=10100' --maxrows 50
991
+ ```
992
+
993
+ Creates local files matching the content entity's `Path` and `Extension` columns:
994
+ ```
995
+ css/
996
+ colors.css # content.Content value
997
+ colors.metadata.json # all column values as JSON
998
+ js/
999
+ app.js
1000
+ app.metadata.json
1001
+ ```
1002
+
1003
+ #### Smart change detection
1004
+
1005
+ When pulling records that already exist locally, the CLI compares your local file modification times against the server's `_LastUpdated` timestamp. If the server has newer data, you'll be prompted:
1006
+
1007
+ 1. **Overwrite** — replace local with server version
1008
+ 2. **Compare** — show a line-by-line diff and selectively merge
1009
+ 3. **Skip** — keep local unchanged
1010
+ 4. **Overwrite all** / **Skip all** — bulk action for remaining files
1011
+
1012
+ After writing, file modification times are synced to the server's `_LastUpdated` to establish a sync point for future comparisons. Use `dbo diff` to compare without pulling.
1013
+
1014
+ ---
1015
+
1016
+ ### `dbo media`
1017
+
1018
+ Get media files from DBO.io.
1019
+
1020
+ ```bash
1021
+ # Get media by UID
1022
+ dbo media albain3dwkofbhnd1qtd1q
1023
+
1024
+ # Save to local file
1025
+ dbo media albain3dwkofbhnd1qtd1q -o logo.png
1026
+
1027
+ # Get by numeric ID
1028
+ dbo media --id 12345 -o file.jpg
1029
+
1030
+ # Get by path
1031
+ dbo media --path assets/images/logo.png -o logo.png
1032
+
1033
+ # Force download
1034
+ dbo media albain3dwkofbhnd1qtd1q --download -o file.pdf
1035
+ ```
1036
+
1037
+ | Flag | Description |
1038
+ |------|-------------|
1039
+ | `<uid>` | Media UID |
1040
+ | `--id <id>` | Media by numeric ID |
1041
+ | `--path <path>` | Media by directory path |
1042
+ | `-o, --output <path>` | Save to local file |
1043
+ | `--download` | Force download (attachment disposition) |
1044
+
1045
+ ---
1046
+
1047
+ ### `dbo upload`
1048
+
1049
+ Upload a binary file to DBO.io.
1050
+
1051
+ ```bash
1052
+ dbo upload image.jpg --bin 12345 --app 67890 --ownership app --path assets/images
1053
+ dbo upload logo.svg --bin 12345 --app 67890 --ownership app --path assets/gfx --name brand-logo
1054
+ dbo upload doc.pdf --bin 12345 --app 67890 --ownership user --path docs --confirm false
1055
+ ```
1056
+
1057
+ | Flag | Description |
1058
+ |------|-------------|
1059
+ | `<filepath>` | Local file to upload |
1060
+ | `--bin <id>` | BinID (required) |
1061
+ | `--app <id>` | AppID (required) |
1062
+ | `--ownership <type>` | Ownership: `app`, `user`, or `system` (required) |
1063
+ | `--path <dir>` | Media path (required) |
1064
+ | `--name <value>` | Override filename |
1065
+ | `-C, --confirm <true\|false>` | Commit (default: `true`) |
1066
+
1067
+ ---
1068
+
1069
+ ### `dbo message`
1070
+
1071
+ Send messages via DBO.io (email, SMS/MMS, chatbot).
1072
+
1073
+ ```bash
1074
+ # Send an email
1075
+ dbo message emailTemplateUID
1076
+
1077
+ # Send a chatbot message with thread
1078
+ dbo message chatbotTemplateUID --thread conversation123
1079
+
1080
+ # Validate without sending
1081
+ dbo message emailTemplateUID --confirm false
1082
+ ```
1083
+
1084
+ | Flag | Description |
1085
+ |------|-------------|
1086
+ | `<uid>` | Content UID for the message template |
1087
+ | `-C, --confirm <true\|false>` | Commit (default: `true`) |
1088
+ | `--thread <id>` | Thread ID for chatbot conversations |
1089
+ | `--json` | Output raw JSON |
1090
+
1091
+ ---
1092
+
1093
+ ### `dbo cache`
1094
+
1095
+ Manage the DBO.io cache.
1096
+
1097
+ ```bash
1098
+ # List all cached items
1099
+ dbo cache list
1100
+
1101
+ # List with metadata
1102
+ dbo cache list --metadata
1103
+
1104
+ # Refresh a specific cache key
1105
+ dbo cache refresh --key 'content:myContentUID'
1106
+ ```
1107
+
1108
+ #### `dbo cache list`
1109
+
1110
+ | Flag | Description |
1111
+ |------|-------------|
1112
+ | `--metadata` | Include cache provider metadata |
1113
+ | `--json` | Output raw JSON |
1114
+
1115
+ #### `dbo cache refresh`
1116
+
1117
+ | Flag | Description |
1118
+ |------|-------------|
1119
+ | `--key <value>` | Cache key to refresh (required) |
1120
+ | `--part <value>` | Cache partition |
1121
+
1122
+ ---
1123
+
1124
+ ### `dbo instance`
1125
+
1126
+ Manage DBO.io instances.
1127
+
1128
+ ```bash
1129
+ # Export the current instance
1130
+ dbo instance export
1131
+
1132
+ # Build an instance
1133
+ dbo instance build instanceUID
1134
+
1135
+ # Validate without executing
1136
+ dbo instance export --confirm false
1137
+ ```
1138
+
1139
+ #### `dbo instance export`
1140
+
1141
+ | Flag | Description |
1142
+ |------|-------------|
1143
+ | `-C, --confirm <true\|false>` | Commit (default: `true`) |
1144
+
1145
+ #### `dbo instance build <uid>`
1146
+
1147
+ | Flag | Description |
1148
+ |------|-------------|
1149
+ | `<uid>` | Instance UID |
1150
+ | `-C, --confirm <true\|false>` | Commit (default: `true`) |
1151
+
1152
+ ---
1153
+
1154
+ ### `dbo diff`
1155
+
1156
+ Compare local files against their server versions and selectively merge changes. This is a one-directional comparison: only server → local changes can be accepted. To push local changes back, use `dbo push`.
1157
+
1158
+ ```bash
1159
+ # Compare all records in the current directory
1160
+ dbo diff
1161
+
1162
+ # Compare a specific file
1163
+ dbo diff assets/css/colors.css
1164
+
1165
+ # Compare all records in a directory
1166
+ dbo diff assets/
1167
+
1168
+ # Display diffs without prompting
1169
+ dbo diff --no-interactive
1170
+
1171
+ # Accept all server changes without prompting
1172
+ dbo diff -y
1173
+ ```
1174
+
1175
+ | Flag | Description |
1176
+ |------|-------------|
1177
+ | `[path]` | File, directory, or `.` (default: current directory) |
1178
+ | `--no-interactive` | Show diffs without prompting to accept |
1179
+ | `-y, --yes` | Accept all server changes automatically |
1180
+ | `-v, --verbose` | Show HTTP request details |
1181
+ | `--domain <host>` | Override domain |
1182
+
1183
+ #### Interactive mode
1184
+
1185
+ For each file with differences, you can:
1186
+ 1. **Accept all changes** — overwrite local with server version
1187
+ 2. **Cherry-pick fields** — accept/skip individual field changes
1188
+ 3. **Skip** — keep local files unchanged
1189
+ 4. **Accept all remaining** — auto-accept for all remaining files
1190
+ 5. **Skip all remaining** — skip all remaining files
1191
+
1192
+ #### Diff output
1193
+
1194
+ Shows a unified diff format with color coding:
1195
+ - Red lines (`-`) — content only in your local file
1196
+ - Green lines (`+`) — content only on the server
1197
+ - Cyan headers — hunk markers showing line positions
1198
+
1199
+ After accepting changes, file modification times are synced to the server's `_LastUpdated` timestamp to establish a new sync point.
1200
+
1201
+ ---
1202
+
1203
+ ### `dbo push`
1204
+
1205
+ Push local files back to DBO.io using metadata from a previous pull. This is the counterpart to `dbo content pull` and `dbo output --save`.
1206
+
1207
+ Files and records matching `.dboignore` patterns are skipped — both by metadata file path (e.g. `*.metadata.json`) and by companion content file path (e.g. a record whose `@Content` points to an ignored `.sql` file). To push an ignored file directly, use `dbo input -d '...'` with an explicit expression.
1208
+
1209
+ #### Round-trip workflow
1210
+
1211
+ ```bash
1212
+ # 1. Pull content to local files
1213
+ dbo content pull --filter 'AppID=10100' --maxrows 10
1214
+
1215
+ # 2. Edit files locally
1216
+ vim css/colors.css
1217
+
1218
+ # 3. Push changes back to DBO
1219
+ dbo push css/colors.css
1220
+ ```
1221
+
1222
+ #### Single file
1223
+
1224
+ ```bash
1225
+ # Push a single file (uses companion .metadata.json)
1226
+ dbo push assets/js/main.js
1227
+
1228
+ # Validate without submitting
1229
+ dbo push assets/js/main.js --confirm false
1230
+
1231
+ # Push only the file content, not metadata columns
1232
+ dbo push assets/js/main.js --content-only
1233
+
1234
+ # Push only metadata changes, skip file content
1235
+ dbo push assets/js/main.js --meta-only
1236
+ ```
1237
+
1238
+ The push command finds `assets/js/main.metadata.json`, reads the UID and entity, and builds input expressions for all columns.
1239
+
1240
+ #### Directory (recursive)
1241
+
1242
+ ```bash
1243
+ # Push all changed records in the current directory
1244
+ dbo push
1245
+
1246
+ # Push all records in a specific directory
1247
+ dbo push assets/
1248
+
1249
+ # Push with auto-accept for all prompts
1250
+ dbo push assets/ -y
1251
+ ```
1252
+
1253
+ Recursively finds all `*.metadata.json` files, verifies `@filename` references exist, and pushes each record.
1254
+
1255
+ #### Path mismatch detection
1256
+
1257
+ If you move a file to a different directory after pulling, the push detects the mismatch:
1258
+
1259
+ ```
1260
+ ⚠ Path mismatch for "main":
1261
+ Metadata Path: css/main.css
1262
+ Current path: assets/css/main.css
1263
+ Update Path column to "assets/css/main.css"? (Y/n)
1264
+ ```
1265
+
1266
+ The `--yes` flag auto-accepts path updates.
1267
+
1268
+ #### Metadata format
1269
+
1270
+ After a pull, metadata files contain `@filename` references for content columns:
1271
+
1272
+ ```json
1273
+ {
1274
+ "_entity": "content",
1275
+ "_contentColumns": ["Content"],
1276
+ "UID": "abc123",
1277
+ "Name": "colors",
1278
+ "Content": "@colors.css",
1279
+ "Extension": "CSS",
1280
+ "Path": "css/colors.css",
1281
+ "Type": "Code"
1282
+ }
1283
+ ```
1284
+
1285
+ The `@colors.css` reference tells push to read the content from that file. All other values are pushed as literal column values.
1286
+
1287
+ | Flag | Description |
1288
+ |------|-------------|
1289
+ | `[path]` | File or directory to push (default: current directory) |
1290
+ | `-C, --confirm <true\|false>` | Commit (default: `true`) |
1291
+ | `--ticket <id>` | Override ticket ID |
1292
+ | `--modify-key <key>` | Provide ModifyKey directly (skips interactive prompt) |
1293
+ | `--row-key <type>` | Override row key type for this invocation (`RowUID` or `RowID`) |
1294
+ | `--meta-only` | Only push metadata, skip file content |
1295
+ | `--content-only` | Only push file content, skip metadata |
1296
+ | `-y, --yes` | Auto-accept all prompts |
1297
+ | `--toe-stepping <true\|false>` | Check server for conflicts before pushing (default: `true`). Set to `false` to skip the check and push unconditionally |
1298
+ | `--no-scripts` | Bypass all script hooks; run default push pipeline |
1299
+ | `--no-build` | Skip the build phase; run push phase only |
1300
+ | `--json` | Output raw JSON |
1301
+ | `--jq <expr>` | Filter JSON response |
1302
+
1303
+ #### Server conflict detection (toe-stepping)
1304
+
1305
+ By default, `dbo push` checks the live server state before submitting changes. For each record being pushed, it fetches the current server version and compares `_LastUpdated` against the local baseline. If another user has modified a record since your last `dbo clone` or `dbo push`, you'll see a conflict warning with the name of the user who made the server-side change and a per-column diff of what changed.
1306
+
1307
+ You can then choose to overwrite the server changes or cancel and pull first. Use `--toe-stepping false` to disable the check entirely, or `--yes` to auto-accept conflicts (useful for CI/scripts).
1308
+
1309
+ ---
1310
+
1311
+ ### `dbo rm`
1312
+
1313
+ Remove a file or directory locally and stage server deletions for the next `dbo push`. Similar to `git rm`.
1314
+
1315
+ #### Single file
1316
+
1317
+ ```bash
1318
+ # Remove a content file (finds companion .metadata.json automatically)
1319
+ dbo rm bins/app/some-file.txt
1320
+
1321
+ # Remove by metadata file directly
1322
+ dbo rm bins/app/some-file.metadata.json
1323
+
1324
+ # Skip confirmation prompt
1325
+ dbo rm -f bins/app/some-file.txt
1326
+
1327
+ # Stage server deletion without deleting local files
1328
+ dbo rm --keep-local bins/app/some-file.txt
1329
+ ```
1330
+
1331
+ #### Directory
1332
+
1333
+ ```bash
1334
+ # Remove a directory and all its contents (prompts for approach)
1335
+ dbo rm bins/app/ui/
1336
+
1337
+ # Remove directory without prompts
1338
+ dbo rm -f bins/app/ui/
1339
+
1340
+ # Stage deletions without removing local files/directories
1341
+ dbo rm --keep-local bins/app/ui/
1342
+ ```
1343
+
1344
+ When removing a directory, the CLI:
1345
+ 1. Looks up the BinID from `.dbo/structure.json`
1346
+ 2. Recursively collects all sub-directories (processed leaves-first)
1347
+ 3. Prompts: "Remove all files and directories", "Prompt for each file", or "Cancel"
1348
+ 4. Stages each file's deletion, then each bin's deletion (`entity:bin`)
1349
+ 5. Removes the local directory (unless `--keep-local`)
1350
+
1351
+ | Flag | Description |
1352
+ |------|-------------|
1353
+ | `<path>` | File, `.metadata.json`, or directory to remove |
1354
+ | `-f, --force` | Skip all confirmation prompts |
1355
+ | `--keep-local` | Only stage server deletions, keep local files/directories |
1356
+ | `--hard` | Immediately delete local files (no `Trash/` move; legacy behavior) |
1357
+
1358
+ #### What rm does (single file)
1359
+
1360
+ 1. **Resolves metadata** — if given a content file, finds the companion `.metadata.json`
1361
+ 2. **Reads row ID** — uses `_id` (shorthand) or derives from entity (e.g., `ContentID`, `MediaID`)
1362
+ 3. **Prompts for confirmation** — "Do you really want to remove this file and all of its nodes?"
1363
+ 4. **Stages deletion** — adds a delete entry to `.dbo/synchronize.json`
1364
+ 5. **Updates app.json** — removes the `@path/to/file.metadata.json` reference from children arrays
1365
+ 6. **Soft-deletes local files** — renames files with `__WILL_DELETE__` prefix (unless `--keep-local` or `--hard`)
1366
+ 7. **After `dbo push`** — successfully deleted records have their `__WILL_DELETE__` files moved to `Trash/`
1367
+
1368
+ Use `--hard` to immediately delete files without the `Trash/` safety net.
1369
+
1370
+ #### synchronize.json
1371
+
1372
+ Pending deletions are stored in `.dbo/synchronize.json`:
1373
+
1374
+ ```json
1375
+ {
1376
+ "delete": [
1377
+ {
1378
+ "UID": "a2dxvg23rk6xsmnum7pdxa",
1379
+ "RowID": 16012,
1380
+ "entity": "content",
1381
+ "name": "nima-test-test",
1382
+ "expression": "RowID:del16012;entity:content=true"
1383
+ }
1384
+ ],
1385
+ "edit": [],
1386
+ "add": []
1387
+ }
1388
+ ```
1389
+
1390
+ The next `dbo push` processes all pending deletions before pushing file changes. Successful deletions are removed from synchronize.json; failures remain staged for retry.
1391
+
1392
+ ---
1393
+
1394
+ ### `dbo add`
1395
+
1396
+ Add a new file to DBO.io by creating a server record. Similar to `git add`, this registers a local file with the server.
1397
+
1398
+ Files matching `.dboignore` patterns are skipped — both in directory-scan mode (`dbo add .`) and single-file mode (`dbo add file.html`). Use `dbo input` to create a record for an ignored file directly.
1399
+
1400
+ #### Single file
1401
+
1402
+ ```bash
1403
+ # Add a file (interactive metadata setup if no .metadata.json exists)
1404
+ dbo add assets/css/colors.css
1405
+
1406
+ # Add with auto-accept prompts
1407
+ dbo add assets/css/colors.css -y
1408
+
1409
+ # Add with ticket ID
1410
+ dbo add assets/css/colors.css --ticket abc123
1411
+ ```
1412
+
1413
+ If the file has no companion `.metadata.json`, an interactive wizard prompts for the entity name, content column, AppID, BinID, SiteID, and Path. It then creates the metadata file and submits the insert.
1414
+
1415
+ #### Directory scan
1416
+
1417
+ ```bash
1418
+ # Scan current directory for un-added files
1419
+ dbo add .
1420
+
1421
+ # Scan a specific directory
1422
+ dbo add assets/
1423
+ ```
1424
+
1425
+ Recursively finds files that either have no `.metadata.json` companion or have metadata without `_CreatedOn` (never been on the server). Lists them and prompts for confirmation before adding.
1426
+
1427
+ When adding multiple files, the entity and column defaults from the first file are reused for subsequent files.
1428
+
1429
+ #### After adding
1430
+
1431
+ After a successful add, the server returns a UID which is written back to the metadata file. To populate all server-side columns (like `_CreatedOn`, `Extension`, etc.), run:
1432
+
1433
+ ```bash
1434
+ dbo pull -e content <uid>
1435
+ ```
1436
+
1437
+ #### Metadata generated by add
1438
+
1439
+ Minimal (no optional fields provided):
1440
+ ```json
1441
+ {
1442
+ "Name": "colors",
1443
+ "Path": "assets/css/colors.css",
1444
+ "Content": "@colors.css",
1445
+ "_entity": "content",
1446
+ "_contentColumns": ["Content"]
1447
+ }
1448
+ ```
1449
+
1450
+ With optional fields (only included if the user provides values during the wizard):
1451
+ ```json
1452
+ {
1453
+ "AppID": 10100,
1454
+ "BinID": 11045,
1455
+ "SiteID": 10061,
1456
+ "Name": "colors",
1457
+ "Path": "assets/css/colors.css",
1458
+ "Content": "@colors.css",
1459
+ "_entity": "content",
1460
+ "_contentColumns": ["Content"]
1461
+ }
1462
+ ```
1463
+
1464
+ The `@colors.css` reference tells the CLI to read the file content from `colors.css` in the same directory.
1465
+
1466
+ | Flag | Description |
1467
+ |------|-------------|
1468
+ | `<path>` | File or `.` to scan current directory |
1469
+ | `-C, --confirm <true\|false>` | Commit (default: `true`) |
1470
+ | `--ticket <id>` | Override ticket ID |
1471
+ | `--modify-key <key>` | Provide ModifyKey directly (skips interactive prompt) |
1472
+ | `--row-key <type>` | Row key type (`RowUID` or `RowID`) — `add` always uses `RowID:add1` for new records regardless |
1473
+ | `-y, --yes` | Auto-accept all prompts |
1474
+ | `--json` | Output raw JSON |
1475
+ | `--jq <expr>` | Filter JSON response |
1476
+
1477
+ #### Column filtering
1478
+
1479
+ The `add` and `push` commands never submit these server-managed columns:
1480
+ - `_CreatedOn`, `_LastUpdated` — set by the server
1481
+ - `_LastUpdatedUserID`, `_LastUpdatedTicketID` — session-provided values
1482
+ - `UID` — assigned by the server on insert
1483
+ - `_id` — internal database ID
1484
+
1485
+ ---
1486
+
1487
+ ### Automatic error recovery
1488
+
1489
+ The `input`, `push`, and `add` commands automatically detect recoverable server errors and prompt for missing values instead of failing immediately.
1490
+
1491
+ #### Ticket error recovery
1492
+
1493
+ When the server returns a `ticket_error` (record update requires a Ticket ID), the CLI prompts with interactive recovery options:
1494
+
1495
+ ```
1496
+ ⚠ This record update requires a Ticket ID.
1497
+ ? Record update requires a Ticket ID:
1498
+ ❯ Apply a Ticket ID to this record and resubmit
1499
+ Apply a Ticket ID to all updates in this transaction, and update my current Ticket ID reference
1500
+ Skip this record update
1501
+ Skip all updates that require a Ticket ID
1502
+ ```
1503
+
1504
+ #### Ticket suggestions
1505
+
1506
+ When `TicketSuggestionOutput` is configured in `.dbo/config.json` (set during `dbo init`), the CLI automatically fetches relevant ticket suggestions from the server and presents them as selectable choices:
1507
+
1508
+ ```
1509
+ ? Select a Ticket ID:
1510
+ ❯ 1 (TKT-001): Fix login page [login-fix]
1511
+ 2 (TKT-002): Update dashboard [dashboard-v2]
1512
+ 3 (TKT-003): Refactor auth [auth-refactor]
1513
+ Enter a Ticket ID manually…
1514
+ ```
1515
+
1516
+ The suggestions are fetched from the configured output endpoint, filtered by the current record's UID. Users can arrow-key through the list to select a ticket, or choose "Enter a Ticket ID manually" for custom input.
1517
+
1518
+ If `TicketSuggestionOutput` is not configured or the fetch fails, the CLI falls back to a plain text input prompt.
1519
+
1520
+ When the server returns a `repo_mismatch` (Ticket ID belongs to a different repository), the CLI prompts:
1521
+
1522
+ ```
1523
+ ⚠ Ticket "TICKET-123" is for another repository.
1524
+ ? The Ticket ID of "TICKET-123" is for another Repository:
1525
+ ❯ Commit anyway
1526
+ Submit with another Ticket ID
1527
+ Skip this record
1528
+ Commit all transactions with this ID anyway
1529
+ Commit all transactions with another Ticket ID, and update my current Ticket ID reference
1530
+ Skip all
1531
+ ```
1532
+
1533
+ Ticket selections are stored in `.dbo/ticketing.local.json` for reuse across submissions. Per-record tickets are cleaned up after successful submission; the global ticket persists until explicitly cleared. The `--ticket` flag always takes precedence over stored tickets.
1534
+
1535
+ #### Ticket ID required (legacy)
1536
+
1537
+ When the server returns `ticket_lookup_required_error`, the CLI prompts:
1538
+
1539
+ ```
1540
+ ⚠ This operation requires a Ticket ID.
1541
+ ? Ticket ID Required: ___
1542
+ ```
1543
+
1544
+ The submission is then retried with `_OverrideTicketID`. To skip the prompt, pass `--ticket <id>` upfront.
1545
+
1546
+ #### Pre-submission ticket prompt
1547
+
1548
+ When a stored ticket exists in `.dbo/ticketing.local.json`, the CLI prompts before batch submissions (`push`, `input`, `add`, `content deploy`, `deploy`):
1549
+
1550
+ ```
1551
+ ? Use stored Ticket ID "TICKET-123" for this submission?
1552
+ ❯ Yes, use "TICKET-123"
1553
+ Use a different ticket for this submission only
1554
+ Use a different ticket for this and future submissions
1555
+ No, clear stored ticket
1556
+ Cancel submission
1557
+ ```
1558
+
1559
+ - **Yes** — applies the stored ticket to all records in this submission
1560
+ - **Different ticket (this submission only)** — prompts for a ticket ID, uses it for all records in this invocation without updating `ticketing.local.json`
1561
+ - **Different ticket (this and future)** — prompts for a ticket ID, updates `ticketing.local.json`, and uses it for this and all future submissions
1562
+ - **No, clear** — removes the stored `ticket_id` and proceeds without a ticket
1563
+ - **Cancel** — aborts the submission
1564
+
1565
+ #### `.dbo/ticketing.local.json`
1566
+
1567
+ Stores ticket IDs for automatic application during submissions:
1568
+
1569
+ ```json
1570
+ {
1571
+ "ticket_id": "TICKET-123",
1572
+ "records": [
1573
+ {
1574
+ "UID": "a2dxvg23rk6xsmnum7pdxa",
1575
+ "RowID": 16012,
1576
+ "entity": "content",
1577
+ "ticket_id": "TICKET-456",
1578
+ "expression": "RowID:16012;column:content._LastUpdatedTicketID=TICKET-456"
1579
+ }
1580
+ ]
1581
+ }
1582
+ ```
1583
+
1584
+ - `ticket_id` — Global ticket applied to all submissions until cleared
1585
+ - `records` — Per-record tickets (auto-cleared after successful submission)
1586
+ - `--ticket` flag always takes precedence over stored tickets
1587
+
1588
+ #### ModifyKey protection (locked/production apps)
1589
+
1590
+ When an app has a `ModifyKey` set (production/locked mode), the CLI guards all submission commands (`push`, `input`, `add`, `content deploy`, `deploy`) with an interactive prompt:
1591
+
1592
+ ```
1593
+ ⚠ This app is locked (production mode). A ModifyKey is required to submit changes.
1594
+ ? This app has a ModifyKey set. How would you like to proceed?
1595
+ ❯ Enter the ModifyKey to proceed
1596
+ Cancel submission
1597
+ ```
1598
+
1599
+ The ModifyKey is detected and stored during `dbo clone`. If the key wasn't stored locally but the server requires one, the CLI reactively prompts after the first failed submission:
1600
+
1601
+ ```
1602
+ ⚠ This app requires a ModifyKey. The key has not been set locally (try re-running `dbo clone`).
1603
+ ? A ModifyKey is required. How would you like to proceed?
1604
+ ❯ Enter the ModifyKey to retry
1605
+ Cancel submission
1606
+ ```
1607
+
1608
+ On successful reactive entry, the key is saved to `.dbo/config.json` for future use.
1609
+
1610
+ To bypass the interactive prompt entirely, pass `--modify-key <key>` on any submission command:
1611
+
1612
+ ```bash
1613
+ dbo push . --modify-key mySecretKey
1614
+ dbo input -d '...' --modify-key mySecretKey
1615
+ dbo add myfile.css --modify-key mySecretKey
1616
+ ```
1617
+
1618
+ #### User identity required
1619
+
1620
+ When the server returns an error mentioning `LoggedInUser_UID`, `LoggedInUserID`, `CurrentUserID`, or `UserID`, the CLI checks for a stored user identity from `dbo login`:
1621
+
1622
+ ```
1623
+ ⚠ This operation requires an authenticated user (LoggedInUser_UID).
1624
+ Your session may have expired, or you may not be logged in.
1625
+ You can log in with "dbo login" to avoid this prompt in the future.
1626
+ Stored session user UID: albain3dwkofbhnd1qtd1q
1627
+ ? User UID Required:
1628
+ ❯ Use session user (UID: albain3dwkofbhnd1qtd1q)
1629
+ Enter a different User UID
1630
+ ```
1631
+
1632
+ If no stored user info is available, it prompts for direct input. The CLI automatically determines whether the server needs a UID or numeric ID based on the error message pattern.
1633
+
1634
+ ---
1635
+
1636
+ ### `dbo install` (alias: `dbo i`)
1637
+
1638
+ Install or upgrade dbo cli components including the CLI itself, plugins, and Claude Code integration.
1639
+
1640
+ ```bash
1641
+ # Interactive — choose what to install
1642
+ dbo install
1643
+
1644
+ # Install/upgrade CLI from npm (latest)
1645
+ dbo i dbo
1646
+ dbo i dbo@latest
1647
+
1648
+ # Install a specific CLI version
1649
+ dbo i dbo@0.4.1
1650
+
1651
+ # Install CLI from local source directory
1652
+ dbo install /path/to/local/cli/src
1653
+
1654
+ # Install/upgrade Claude Code commands
1655
+ dbo install plugins
1656
+ dbo install claudecommands
1657
+
1658
+ # Install Claude Code commands globally (shared across projects)
1659
+ dbo install plugins --global
1660
+
1661
+ # Explicitly install to project directory
1662
+ dbo install plugins --local
1663
+
1664
+ # Install Claude Code CLI (if not present) + commands
1665
+ dbo install claudecode
1666
+
1667
+ # Install/upgrade a specific command plugin
1668
+ dbo install --claudecommand dbo
1669
+
1670
+ # Install a specific command globally
1671
+ dbo install --claudecommand dbo --global
1672
+ ```
1673
+
1674
+ | Flag | Description |
1675
+ |------|-------------|
1676
+ | `[target]` | What to install: `dbo[@version]`, `plugins`, `claudecommands`, `claudecode`, or a local path |
1677
+ | `--claudecommand <name>` | Install/upgrade a specific command by name |
1678
+ | `-g, --global` | Install commands to user home directory (`~/.claude/commands/`) |
1679
+ | `--local` | Install commands to project directory (`.claude/commands/`) |
1680
+
1681
+ Smart behavior:
1682
+ - If the CLI is already installed, prompts to upgrade (with version comparison)
1683
+ - If plugins are already installed and up to date, reports "already up to date"
1684
+ - If plugins differ from source, prompts to upgrade to the latest version
1685
+ - Compares file hashes — unchanged files are skipped
1686
+ - Adds project-scoped plugins to `.gitignore` (source of truth is `plugins/claude/` at repo root)
1687
+ - Per-plugin scope (project or global) is stored in `.dbo/config.local.json` and remembered for future upgrades
1688
+ - On re-install (e.g. after `npm install` or `npm link`), scope is inferred automatically from the global plugin registry (`~/.claude/plugins/installed_plugins.json`) or existing project installation — no prompt is shown
1689
+ - On first install with no prior preference and no existing installation, prompts for scope
1690
+ - `--global` / `--local` flags override stored preferences and update them
1691
+
1692
+ ---
1693
+
1694
+ ### `dbo deploy`
1695
+
1696
+ Deploy files to DBO.io using a `.dbo/deploy_config.json` manifest or direct arguments.
1697
+
1698
+ ```bash
1699
+ # Deploy a named entry from the manifest
1700
+ dbo deploy css:colors
1701
+
1702
+ # Deploy all entries
1703
+ dbo deploy --all
1704
+
1705
+ # Deploy with ticket ID
1706
+ dbo deploy js:app --ticket abc123
1707
+
1708
+ # Validate without deploying
1709
+ dbo deploy css:colors --confirm false
1710
+
1711
+ # Deploy a multipart (binary) entry from manifest
1712
+ dbo deploy img:logo
1713
+ ```
1714
+
1715
+ | Flag | Description |
1716
+ |------|-------------|
1717
+ | `<name>` | Deployment name from `.dbo/deploy_config.json` |
1718
+ | `--all` | Deploy all entries in the manifest |
1719
+ | `-C, --confirm <true\|false>` | Commit (default: `true`) |
1720
+ | `--ticket <id>` | Override ticket ID |
1721
+ | `--modify-key <key>` | Provide ModifyKey directly (skips interactive prompt) |
1722
+ | `--row-key <type>` | Override row key type for this invocation (`RowUID` or `RowID`) |
1723
+ | `--json` | Output raw JSON |
1724
+ | `-v, --verbose` | Show HTTP request details |
1725
+ | `--domain <host>` | Override domain |
1726
+
1727
+ The `deploy` command includes the same automatic error recovery as `push`, `input`, and `add` — including ticket error handling, repository mismatch recovery, user identity prompts, and ModifyKey protection. When a stored ticket exists, you'll be prompted before the first submission (see [Pre-submission ticket prompt](#pre-submission-ticket-prompt)).
1728
+
1729
+ #### `.dbo/deploy_config.json` manifest
1730
+
1731
+ Create a `.dbo/deploy_config.json` file to define named deployments:
1732
+
1733
+ ```json
1734
+ {
1735
+ "deployments": {
1736
+ "css:colors": {
1737
+ "uid": "albain3dwkofbhnd1qtd1q",
1738
+ "file": "assets/css/colors.css"
1739
+ },
1740
+ "js:app": {
1741
+ "uid": "rncjivlghu65bmkbjnxynq",
1742
+ "file": "assets/js/app.js"
1743
+ },
1744
+ "doc:colors": {
1745
+ "uid": "l2uv2gu8gu6ziyluuncv0w",
1746
+ "file": "docs/colors.md",
1747
+ "entity": "extension",
1748
+ "column": "Text"
1749
+ },
1750
+ "img:logo": {
1751
+ "uid": "x9fk2m3npqrs7tuvwyz1ab",
1752
+ "file": "assets/images/logo.png",
1753
+ "multipart": true
1754
+ },
1755
+ "upload:icons": {
1756
+ "uid": "7ddf10982a96457fa4f440",
1757
+ "file": "assets/css/launchpad-icons.css",
1758
+ "multipart": true,
1759
+ "filename": "launchpad-icons.css"
1760
+ }
1761
+ }
1762
+ }
1763
+ ```
1764
+
1765
+ | Field | Description | Default |
1766
+ |-------|-------------|---------|
1767
+ | `uid` | Target record UID (required) | — |
1768
+ | `file` | Local file path (required) | — |
1769
+ | `entity` | Target entity name | `content` (`media` when `multipart: true`) |
1770
+ | `column` | Target column name | `Content` (`File` when `multipart: true`) |
1771
+ | `multipart` | Use multipart/form-data upload (for binary files) | `false` |
1772
+ | `filename` | Set the `Filename` column on the target record | basename of `file` |
1773
+
1774
+ This replaces the curl commands typically embedded in `package.json` scripts.
1775
+
1776
+ #### Non-interactive mode (npm scripts)
1777
+
1778
+ When running `dbo deploy` (or any submission command) inside npm scripts or piped commands where stdin is not a TTY, the CLI automatically skips all interactive prompts and uses stored credentials:
1779
+
1780
+ - **Stored ticket** — auto-applied from `.dbo/ticketing.local.json`
1781
+ - **ModifyKey** — auto-applied from `.dbo/config.json` (`AppModifyKey`)
1782
+ - **User identity** — auto-applied from `.dbo/credentials.json`
1783
+
1784
+ If a required value is missing and no interactive prompt is possible, the command fails with a clear error message explaining how to set up the missing value.
1785
+
1786
+ Example `package.json` scripts:
1787
+
1788
+ ```json
1789
+ {
1790
+ "scripts": {
1791
+ "deploy:css": "dbo deploy css:colors && dbo deploy css:layout",
1792
+ "deploy:docs": "dbo deploy doc:readme && dbo deploy doc:api",
1793
+ "deploy:all": "dbo deploy --all"
1794
+ }
1795
+ }
1796
+ ```
1797
+
1798
+ To set up for non-interactive use:
1799
+ 1. Run `dbo login` to store user credentials
1800
+ 2. Run `dbo clone` to store the ModifyKey (if applicable)
1801
+ 3. Set a ticket interactively once — it persists in `ticketing.local.json` for future npm script runs
1802
+
1803
+ ---
1804
+
1805
+ ## Script Hooks
1806
+
1807
+ Script hooks let you define build and push lifecycle commands in `.dbo/scripts.json`. Hooks run automatically during `dbo push` and can also be triggered independently with `dbo build` and `dbo run`.
1808
+
1809
+ ### Configuration Files
1810
+
1811
+ | File | Tracked | Purpose |
1812
+ |------|---------|---------|
1813
+ | `.dbo/scripts.json` | Yes | Shared hook definitions (committed to git) |
1814
+ | `.dbo/scripts.local.json` | No | Per-user overrides (gitignored) |
1815
+
1816
+ ### Top-level Keys
1817
+
1818
+ | Key | Description |
1819
+ |-----|-------------|
1820
+ | `scripts` | Global hooks and named scripts (apply to all targets) |
1821
+ | `targets` | Per-file or per-directory hooks (highest priority) |
1822
+ | `entities` | Per-entity-type hooks (e.g., `content`, `extension.control`) |
1823
+
1824
+ ### Example `.dbo/scripts.json`
1825
+
1826
+ ```json
1827
+ {
1828
+ "scripts": {
1829
+ "prepush": "echo pushing $DBO_TARGET"
1830
+ },
1831
+ "targets": {
1832
+ "lib/bins/app/assets/js/operator.js": {
1833
+ "build": "rollup -c src/rollup_config.mjs",
1834
+ "push": false
1835
+ }
1836
+ },
1837
+ "entities": {
1838
+ "extension.control": {
1839
+ "prebuild": "npm run compile-controls"
1840
+ }
1841
+ }
1842
+ }
1843
+ ```
1844
+
1845
+ ### Lifecycle Hooks
1846
+
1847
+ | Hook | Phase | Description |
1848
+ |------|-------|-------------|
1849
+ | `prebuild` | Build | Runs before build |
1850
+ | `build` | Build | Main build step |
1851
+ | `postbuild` | Build | Runs after build |
1852
+ | `prepush` | Push | Runs before push |
1853
+ | `push` | Push | Custom push (replaces default HTTP submit) |
1854
+ | `postpush` | Push | Runs after push |
1855
+
1856
+ ### Resolution Order
1857
+
1858
+ Hooks resolve per-hook from lowest to highest priority:
1859
+
1860
+ 1. **Global** (`scripts`) — applies to all targets
1861
+ 2. **Entity** (`entities`) — applies to targets matching the entity type
1862
+ 3. **Target** (`targets`) — applies to a specific file or directory
1863
+
1864
+ A target can override `build` while the global `prepush` still applies.
1865
+
1866
+ ### Hook Value Types
1867
+
1868
+ | Value | Behavior |
1869
+ |-------|----------|
1870
+ | `"command"` | Run as shell command |
1871
+ | `["cmd1", "cmd2"]` | Run sequentially; fail-fast on first non-zero exit |
1872
+ | `false` | Skip (for `push`: skip HTTP submit) |
1873
+ | `true` / omitted | Use default behavior |
1874
+
1875
+ ### Environment Variables
1876
+
1877
+ These env vars are injected into all hook processes:
1878
+
1879
+ | Variable | Description |
1880
+ |----------|-------------|
1881
+ | `DBO_TARGET` | Relative file path being processed |
1882
+ | `DBO_ENTITY` | Entity type (e.g., `content`, `extension`) |
1883
+ | `DBO_DOMAIN` | Configured domain |
1884
+ | `DBO_APP` | App short name |
1885
+ | `DBO_APP_UID` | App UID |
1886
+
1887
+ ### Push Flags
1888
+
1889
+ | Flag | Description |
1890
+ |------|-------------|
1891
+ | `--no-scripts` | Bypass all script hooks; run default push pipeline |
1892
+ | `--no-build` | Skip build phase; run push phase only |
1893
+
1894
+ ### `dbo build [path]`
1895
+
1896
+ Runs the build lifecycle (`prebuild` → `build` → `postbuild`) without pushing.
1897
+
1898
+ ```bash
1899
+ # Build a specific target
1900
+ dbo build lib/bins/app/assets/js/operator.js
1901
+
1902
+ # Build all targets with a build hook
1903
+ dbo build
1904
+ ```
1905
+
1906
+ ### `dbo run [script-name]`
1907
+
1908
+ Runs a named global script from `.dbo/scripts.json` (like `npm run`). Automatically runs `pre<name>` and `post<name>` scripts if defined.
1909
+
1910
+ ```bash
1911
+ # List all available scripts
1912
+ dbo run
1913
+
1914
+ # Run a specific script
1915
+ dbo run prepush
1916
+ ```
1917
+
1918
+ ---
1919
+
1920
+ ## Global Flags
1921
+
1922
+ These flags are available on most commands:
1923
+
1924
+ | Flag | Description |
1925
+ |------|-------------|
1926
+ | `-C, --confirm <true\|false>` | Commit changes (default: `true`). Use `false` for validation only |
1927
+ | `--json` | Output raw JSON response with syntax highlighting |
1928
+ | `--jq <expr>` | Filter JSON response with a jq-like expression (implies `--json`) |
1929
+ | `-v, --verbose` | Show HTTP request details (method, URL, body) |
1930
+ | `--domain <host>` | Override the configured domain for this request |
1931
+ | `-h, --help` | Show help for any command |
1932
+
1933
+ ---
1934
+
1935
+ ## JSON Filtering (`--jq`)
1936
+
1937
+ The `--jq` flag provides built-in jq-like JSON filtering without requiring `jq` to be installed. It supports the most common patterns:
1938
+
1939
+ ```bash
1940
+ # Pretty-print the entire response (with syntax highlighting)
1941
+ dbo output -e user --jq '.'
1942
+
1943
+ # Extract a specific key
1944
+ dbo output -e user --jq '.Payload'
1945
+
1946
+ # Nested key access
1947
+ dbo input -d '...' --jq '.Payload.Results.Add'
1948
+
1949
+ # Pluck a field from every item in an array
1950
+ dbo output -e user --jq '.Payload.Results.Add[].UID'
1951
+
1952
+ # Array index
1953
+ dbo output -e user --jq '.Payload.Results.Add[0]'
1954
+
1955
+ # Pipe: iterate then access
1956
+ dbo output -e user --jq '.Payload.Results.Add[] | .UID'
1957
+
1958
+ # Use with any command that returns JSON
1959
+ dbo cache list --jq '.Payload'
1960
+ dbo message myUID --jq '.Successful'
1961
+ ```
1962
+
1963
+ ### Supported expressions
1964
+
1965
+ | Expression | Description |
1966
+ |-----------|-------------|
1967
+ | `.` | Identity (entire response) |
1968
+ | `.key` | Access a top-level key |
1969
+ | `.key.nested` | Nested key access |
1970
+ | `.[0]` | Array index |
1971
+ | `.[]` | Iterate array |
1972
+ | `.[].field` | Pluck field from each array item |
1973
+ | `.[] \| .field` | Pipe: iterate then access |
1974
+ | `.["key.name"]` | Bracket notation for keys with dots |
1975
+
1976
+ When `--jq` is used, the API request is automatically made with `_template=json_raw`.
1977
+
1978
+ ### JSON syntax highlighting
1979
+
1980
+ Both `--json` and `--jq` output use syntax highlighting:
1981
+ - **Keys** in cyan
1982
+ - **Strings** in green
1983
+ - **Numbers** in yellow
1984
+ - **Booleans/null** in magenta
1985
+
1986
+ ---
1987
+
1988
+ ## DBO API Parameter Reference
1989
+
1990
+ The DBO.io API uses a token architecture for dynamic parameters. All parameters are passed as URL query string key-value pairs.
1991
+
1992
+ ### Token Syntax
1993
+
1994
+ Parameters follow the token delimiter system:
1995
+
1996
+ ```
1997
+ _tokenType@reference$target!defaultValue:modifier=value
1998
+ ```
1999
+
2000
+ | Delimiter | Purpose | Example |
2001
+ |-----------|---------|---------|
2002
+ | `_` | Prefix for token type | `_filter`, `_sort`, `_limit` |
2003
+ | `@` | Reference (column, field, key) | `_filter@FirstName=John` |
2004
+ | `$` | Target (scope to a specific output/entity) | `_limit$outputUid=100` |
2005
+ | `!` | Default value (fallback) | `_filter@Status!active=value` |
2006
+ | `:` | Modifier(s) | `_filter@Name:Contains=john` |
2007
+
2008
+ ### Output Parameters
2009
+
2010
+ These parameters control the output endpoint behavior (`/api/output/{uid}` and `/api/output/entity/{entityUid}`):
2011
+
2012
+ #### Filtering
2013
+
2014
+ ```
2015
+ _filter@ColumnName=value # exact match (default)
2016
+ _filter@ColumnName:Contains=value # LIKE %value%
2017
+ _filter@ColumnName:StartsWith=value # LIKE value%
2018
+ _filter@ColumnName:EndsWith=value # LIKE %value
2019
+ _filter@ColumnName:LessThan=value # < comparison
2020
+ _filter@ColumnName:LessThanOrEqualTo=value # <= comparison
2021
+ _filter@ColumnName:GreaterThan=value # > comparison
2022
+ _filter@ColumnName:GreaterThanOrEqualTo=value # >= comparison
2023
+ _filter@ColumnName:Contains,And=value # AND logic (default is OR)
2024
+ _filter@ColumnName:Contains,Exclude=value # NOT LIKE
2025
+ _filter$outputTarget@ColumnName=value # scoped to specific output
2026
+ ```
2027
+
2028
+ #### Sorting
2029
+
2030
+ ```
2031
+ _sort=ColumnName # ascending (default)
2032
+ _sort=ColumnName:ASC # explicit ascending
2033
+ _sort=ColumnName:DESC # descending
2034
+ _sort=Column1:ASC,Column2:DESC # multiple sorts (comma-separated)
2035
+ _sort=ColumnName ASC # space-separated also works
2036
+ ```
2037
+
2038
+ Multiple `_sort` parameters can be specified; earlier sorts take precedence.
2039
+
2040
+ #### Pagination
2041
+
2042
+ ```
2043
+ _limit=30 # max 30 rows
2044
+ _limit=10-30 # rows 10 through 30 (range)
2045
+ _limit=10&_page=3 # 10 rows per page, page 3
2046
+ _rowcount=false # disable row count for performance
2047
+ ```
2048
+
2049
+ Deprecated (still accepted): `_maxrows`, `_rows`, `_rowsperpage`
2050
+
2051
+ #### Search
2052
+
2053
+ ```
2054
+ _search=keyword # full-text search across searchable columns
2055
+ _search@ColumnName=keyword # search specific column
2056
+ ```
2057
+
2058
+ #### Template & Format
2059
+
2060
+ ```
2061
+ _template=json_raw # system template name: json_raw, json_indented, json, html, csv, xml, txt, pdf
2062
+ _template=3iX9fHFTL064Shgol8Bktw # content UID (custom template)
2063
+ _format_values=true # enable value formatting in json_raw
2064
+ _mime=application/json # override MIME/content type
2065
+ _escape_html=false # disable HTML escaping of data values
2066
+ ```
2067
+
2068
+ > **`_format` is deprecated.** Do not use `_format` — use `_template` instead. The `_format` key is demoted and retained only for backwards compatibility in the API. Do not use `_format` in combination with `_template` — combining both in a single request causes broken responses.
2069
+
2070
+ #### Display Control
2071
+
2072
+ ```
2073
+ _display@tagName=show # show a template content tag
2074
+ _display@tagName=hide # hide a template content tag
2075
+ _empty_response_code=404 # HTTP status when results are empty
2076
+ _fallback_content:404=contentUID # render a different content on 404
2077
+ ```
2078
+
2079
+ #### Debug & Profiling
2080
+
2081
+ ```
2082
+ _debug=true # general debug output
2083
+ _debug:sql=true # return SQL without executing
2084
+ _debug:verbose=true # verbose debug
2085
+ _debug:analysis=true # analysis debug
2086
+ _profile=true # MiniProfiler output
2087
+ ```
2088
+
2089
+ Other debug sub-keys: `http_modules`, `instance`, `rewrites`, `cache`, `executable_contents`, `security`, `controllers`, `embeds`, `includes`, `contents`, `template_render`, `tokens`, `messages`, `media`, `request_stack`, `query_execution`, `query_building`
2090
+
2091
+ #### Control Flags
2092
+
2093
+ ```
2094
+ _strict=true # strict error mode
2095
+ _confirm=true # confirmation flag for operations
2096
+ _no_transaction=true # disable transaction wrapping
2097
+ _skip=all # skip execution phases (admin-only)
2098
+ _include=value # include token
2099
+ _security=value # security filter enforcement
2100
+ ```
2101
+
2102
+ ### Data Tokens (used in templates)
2103
+
2104
+ | Token | Description |
2105
+ |-------|-------------|
2106
+ | `#{value@ColumnName}` | Column value from output row |
2107
+ | `#{id}` | Row primary key |
2108
+ | `#{uid}` | Row UID |
2109
+ | `#{CurrentUser@field}` | Current user field (e.g., `FirstName`, `Email`) |
2110
+ | `#{request@key}` | URL parameter value |
2111
+ | `#{session@variable}` | Session variable |
2112
+ | `#{site@field}` | Site field |
2113
+ | `#{date:format}` | Current date/time |
2114
+ | `#{unique:uid}` | Generate unique UID |
2115
+ | `#{count}` | Row count |
2116
+ | `#{page}` | Current page number |
2117
+
2118
+ ### Template Tags
2119
+
2120
+ System tags (used in output templates):
2121
+
2122
+ | Tag | Purpose |
2123
+ |-----|---------|
2124
+ | `<#_row>` | Row template |
2125
+ | `<#_header>` | Header template |
2126
+ | `<#_footer>` | Footer template |
2127
+ | `<#_cell>` | Cell template |
2128
+ | `<#_empty>` | Empty result template |
2129
+ | `<#_noresult>` | No result template |
2130
+ | `<#_prompt>` | Prompt template |
2131
+ | `<#_shared>` | Shared template |
2132
+ | `<#_rowdelimiter>` | Row delimiter |
2133
+ | `<#_celldelimiter>` | Cell delimiter |
2134
+ | `<#_value>` | Value template |
2135
+ | `<#_embed url="...">` | Embed nested content/output |
2136
+
2137
+ User-defined tags use `<#reference>` (no underscore prefix).
2138
+
2139
+ ---
2140
+
2141
+ ## Migration from curl
2142
+
2143
+ The `dbo` CLI is a drop-in replacement for the curl-based workflow. Here's how common operations translate:
2144
+
2145
+ ### Authentication
2146
+
2147
+ **Before:**
2148
+ ```bash
2149
+ echo "my-domain.com" > .domain
2150
+ echo "user@example.com" > .username
2151
+ echo "mypassword" > .password
2152
+ curl --cookie-jar .cookies -K authenticate.curl
2153
+ ```
2154
+
2155
+ **After:**
2156
+ ```bash
2157
+ dbo init --domain my-domain.com --username user@example.com
2158
+ dbo login
2159
+ ```
2160
+
2161
+ ### Edit a record
2162
+
2163
+ **Before:**
2164
+ ```bash
2165
+ curl -K config-data.curl -d "RowID:10065;column:user.FirstName=Jane"
2166
+ ```
2167
+
2168
+ **After:**
2169
+ ```bash
2170
+ dbo input -d 'RowID:10065;column:user.FirstName=Jane'
2171
+ ```
2172
+
2173
+ ### Deploy CSS from a local file
2174
+
2175
+ **Before:**
2176
+ ```bash
2177
+ curl -K config-data.curl --data-urlencode RowUID%3Aalbain3dwkofbhnd1qtd1q%3Bcolumn%3Acontent.Content@assets/css/colors.css
2178
+ ```
2179
+
2180
+ **After:**
2181
+ ```bash
2182
+ dbo content deploy albain3dwkofbhnd1qtd1q assets/css/colors.css
2183
+ ```
2184
+
2185
+ ### Upload a media file
2186
+
2187
+ **Before:**
2188
+ ```bash
2189
+ curl -K config-form.curl -F file=@path/to/image.jpg -F "RowID:add1;column:media.BinID=12345" -F "RowID:add1;column:media.AppID=67890" -F "RowID:add1;column:media.Ownership=app" -F "RowID:add1;column:media.Path=assets/images"
2190
+ ```
2191
+
2192
+ **After:**
2193
+ ```bash
2194
+ dbo upload image.jpg --bin 12345 --app 67890 --ownership app --path assets/images
2195
+ ```
2196
+
2197
+ ### Query data
2198
+
2199
+ **Before:**
2200
+ ```bash
2201
+ curl -b .cookies "https://my-domain.com/api/output/entity/user?_template=json_indented&_filter@FirstName=John"
2202
+ ```
2203
+
2204
+ **After:**
2205
+ ```bash
2206
+ dbo output -e user --filter 'FirstName=John' --template json_indented
2207
+ ```
2208
+
2209
+ ### Cookie compatibility
2210
+
2211
+ The `dbo` CLI writes cookies in Netscape format (same as curl's `--cookie-jar`). You can use the same cookie file with both tools during migration:
2212
+
2213
+ ```bash
2214
+ dbo login
2215
+ curl -b .dbo/cookies.txt https://my-domain.com/api/content/myUID
2216
+ ```
2217
+
2218
+ ---
2219
+
2220
+ ## License
2221
+
2222
+ Copyright manolab, LLC