Summary
The generated CLI currently exposes Appwrite query input through --queries, but in practice users have to pass pre-serialized Appwrite JSON query strings. That format is not intuitive for shell usage, and the current command help/examples do not make the expected syntax clear.
This issue proposes a backwards-compatible CLI UX redesign:
- add ergonomic first-class flags for common query operations
- keep the existing
--queries behavior working unchanged for advanced users and automation
- improve help text, examples, and runtime error hints
Problem
Today, users commonly try forms like:
appwrite databases list-documents --queries 'limit(100)'
appwrite databases list-documents --queries '["limit(100)"]'
Those inputs are forwarded as-is to the API, which then rejects them because the CLI expects each query token to already be an Appwrite JSON query string.
Internally, the CLI already uses serialized JSON query objects in several places, for example:
JSON.stringify({ method: "orderDesc", attribute: "$id" })
JSON.stringify({ method: "limit", values: [100] })
So the current UX is technically consistent, but not intuitive.
Goals
- make common list/filter/sort/pagination operations easy to express from a shell
- avoid requiring JSON arrays or nested escaping for normal usage
- preserve full power for advanced queries
- remain fully backwards compatible with existing
--queries usage
Proposed UX
1. First-class flags for common query operations
Add dedicated flags for the common query methods users expect to use directly from the CLI:
appwrite databases list-documents \
--database-id <DATABASE_ID> \
--collection-id memory \
--sort-desc '$createdAt' \
--limit 5
Suggested initial flag surface:
--limit <number>
--offset <number>
--cursor-after <id>
--cursor-before <id>
--sort-asc <field>
--sort-desc <field>
--select <csv-or-repeatable>
2. Repeatable --where for common filters
Support a shell-friendly repeatable filter flag:
appwrite databases list-documents \
--database-id <DATABASE_ID> \
--collection-id memory \
--where 'status=active' \
--where 'score>=10' \
--sort-desc '$createdAt' \
--limit 5
Initial grammar can target the most common cases first:
field=value
field!=value
field>value
field>=value
field<value
field<=value
field contains value
field search value
field is null
field is not null
field in [a,b,c]
field between [a,b]
This can compile internally into the existing Appwrite JSON query strings.
3. Keep a raw escape hatch for advanced use cases
Advanced users should still have access to raw query input.
Two acceptable options:
- keep
--queries as-is and document it clearly as the low-level interface
- optionally add an alias like
--query-json for readability, while keeping --queries
Example:
appwrite databases list-documents \
--database-id <DATABASE_ID> \
--collection-id memory \
--queries '{"method":"or","values":[...]}'
Backwards Compatibility
This change should be explicitly backwards compatible.
- Existing
--queries behavior remains supported unchanged.
- Existing scripts, CI jobs, and automation using serialized Appwrite query strings continue to work.
- New flags are translated internally into the same JSON query format already used today.
- Users may mix new ergonomic flags with raw
--queries where that combination makes sense.
If mixed usage is allowed, the merge order should be documented and deterministic.
Detailed Implementation Plan
Phase 1: Shared query builder/parsing utilities
Add shared CLI-side utilities in the generated CLI templates to:
- build Appwrite JSON query strings from ergonomic flags
- parse repeatable
--where expressions
- normalize scalar vs array values
- merge generated query strings with existing raw
--queries
This should live in a shared template instead of ad hoc per command.
Phase 2: Command generation changes
Update the CLI command generator so query-capable commands can emit the new ergonomic flags.
Likely touch points:
src/SDK/Language/CLI.php
templates/cli/lib/commands/services/services.ts.twig
- generated command output in
examples/cli/lib/commands/services/*.ts
The generator should only add these flags where query parameters are actually supported.
Phase 3: Help text and examples
Update generated help and docs so users can discover the new syntax immediately.
This should include:
- command help text for
--queries clarifying that it is raw JSON-query input
- examples for common cases like latest documents, pagination, and filtering
- generated docs/examples in
examples/cli/docs/examples/...
Phase 4: Runtime error guidance
When the API returns errors like:
Invalid query
Invalid query method
Syntax error
show a targeted CLI hint with a correct example and point users to the ergonomic flags where available.
Phase 5: Verification
After template changes:
- regenerate the CLI via
php example.php cli
- rebuild the binary
- verify generated command help and example docs
- verify raw
--queries still works exactly as before
- verify new flags generate equivalent query payloads
Suggested Acceptance Criteria
--limit, --offset, --sort-asc, and --sort-desc are supported on query-capable list commands.
- A repeatable
--where flag is supported for common comparison/filter operations.
--queries remains fully supported and unchanged.
- Help output clearly distinguishes ergonomic flags from raw query input.
- Generated docs include working examples for common list/filter/sort usage.
- Invalid query errors include actionable hints.
- Regenerated CLI output in
examples/cli/ reflects the new UX.
Non-Goals
- removing or breaking
--queries
- requiring all Appwrite query methods to be supported in
--where on day one
- changing the Appwrite API query format itself
Why this belongs in sdk-generator
The confusing UX is produced by the generated CLI surface and its generated docs/examples. Even if website docs also need updates elsewhere, the source of truth for the CLI command interface lives here.
Example End State
Simple latest rows query:
appwrite databases list-documents \
--database-id <DATABASE_ID> \
--collection-id memory \
--sort-desc '$createdAt' \
--limit 5 \
--json
Advanced raw query remains available:
appwrite databases list-documents \
--database-id <DATABASE_ID> \
--collection-id memory \
--queries '{"method":"orderDesc","attribute":"$createdAt"}' '{"method":"limit","values":[5]}' \
--json
Summary
The generated CLI currently exposes Appwrite query input through
--queries, but in practice users have to pass pre-serialized Appwrite JSON query strings. That format is not intuitive for shell usage, and the current command help/examples do not make the expected syntax clear.This issue proposes a backwards-compatible CLI UX redesign:
--queriesbehavior working unchanged for advanced users and automationProblem
Today, users commonly try forms like:
Those inputs are forwarded as-is to the API, which then rejects them because the CLI expects each query token to already be an Appwrite JSON query string.
Internally, the CLI already uses serialized JSON query objects in several places, for example:
So the current UX is technically consistent, but not intuitive.
Goals
--queriesusageProposed UX
1. First-class flags for common query operations
Add dedicated flags for the common query methods users expect to use directly from the CLI:
Suggested initial flag surface:
--limit <number>--offset <number>--cursor-after <id>--cursor-before <id>--sort-asc <field>--sort-desc <field>--select <csv-or-repeatable>2. Repeatable
--wherefor common filtersSupport a shell-friendly repeatable filter flag:
Initial grammar can target the most common cases first:
field=valuefield!=valuefield>valuefield>=valuefield<valuefield<=valuefield contains valuefield search valuefield is nullfield is not nullfield in [a,b,c]field between [a,b]This can compile internally into the existing Appwrite JSON query strings.
3. Keep a raw escape hatch for advanced use cases
Advanced users should still have access to raw query input.
Two acceptable options:
--queriesas-is and document it clearly as the low-level interface--query-jsonfor readability, while keeping--queriesExample:
Backwards Compatibility
This change should be explicitly backwards compatible.
--queriesbehavior remains supported unchanged.--querieswhere that combination makes sense.If mixed usage is allowed, the merge order should be documented and deterministic.
Detailed Implementation Plan
Phase 1: Shared query builder/parsing utilities
Add shared CLI-side utilities in the generated CLI templates to:
--whereexpressions--queriesThis should live in a shared template instead of ad hoc per command.
Phase 2: Command generation changes
Update the CLI command generator so query-capable commands can emit the new ergonomic flags.
Likely touch points:
src/SDK/Language/CLI.phptemplates/cli/lib/commands/services/services.ts.twigexamples/cli/lib/commands/services/*.tsThe generator should only add these flags where query parameters are actually supported.
Phase 3: Help text and examples
Update generated help and docs so users can discover the new syntax immediately.
This should include:
--queriesclarifying that it is raw JSON-query inputexamples/cli/docs/examples/...Phase 4: Runtime error guidance
When the API returns errors like:
Invalid queryInvalid query methodSyntax errorshow a targeted CLI hint with a correct example and point users to the ergonomic flags where available.
Phase 5: Verification
After template changes:
php example.php cli--queriesstill works exactly as beforeSuggested Acceptance Criteria
--limit,--offset,--sort-asc, and--sort-descare supported on query-capable list commands.--whereflag is supported for common comparison/filter operations.--queriesremains fully supported and unchanged.examples/cli/reflects the new UX.Non-Goals
--queries--whereon day oneWhy this belongs in
sdk-generatorThe confusing UX is produced by the generated CLI surface and its generated docs/examples. Even if website docs also need updates elsewhere, the source of truth for the CLI command interface lives here.
Example End State
Simple latest rows query:
Advanced raw query remains available: