
Docyrus Cli App
- 707 installs
- 13 repo stars
- Updated July 15, 2026
- docyrus/agent-skills
docyrus-cli-app is a Claude Code skill that drives Docyrus platform operations from the shell—authentication, environments, data records, Studio schema objects, automations, and email—for developers building Docyrus-back
About
docyrus-cli-app is a skill from docyrus/agent-skills centered on the docyrus terminal CLI for full platform control without the web UI. It covers authentication, tenant and environment switching, OpenAPI discovery, and Bun-powered terminal UI via docyrus tui. Data operations use docyrus ds for listing and managing records. Studio commands manage schema objects including data sources, fields, enums, data views, forms, webforms, and HTML, PDF, or DOCX export templates plus email templates. Automation subcommands configure triggers and action nodes, while messaging lists tenant email accounts and sends mail. Developers reach for docyrus-cli-app when an agent must script schema changes, seed records, test automations, or send template email during Docyrus app development. Triggers include explicit docyrus command names such as docyrus studio form or docyrus studio html-template in the user request.
- Covers `docyrus` context, `auth`, `env list` / `env use`, and environment or tenant switching
- `docyrus ds` for querying and managing data records from the terminal
- `docyrus studio` for data sources, fields, enums, data views, forms, webforms, and HTML/PDF/DOCX/email export templates
- `docyrus automation` for triggers and action nodes plus `docyrus messaging` for accounts and send-email flows
- `docyrus discover` for tenant OpenAPI specs and `docyrus tui` for Bun-powered terminal UI workflows
Docyrus Cli App by the numbers
- 707 all-time installs (skills.sh)
- Ranked #107 of 550 CLI & Terminal skills by installs in the Skillselion catalog
- Security screen: HIGH risk (skills.sh audit)
- Data as of Jul 29, 2026 (Skillselion catalog sync)
npx skills add https://github.com/docyrus/agent-skills --skill docyrus-cli-appAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 707 |
|---|---|
| repo stars | ★ 13 |
| Security audit | 2 / 3 scanners passed |
| Last updated | July 15, 2026 |
| Repository | docyrus/agent-skills ↗ |
How do you manage Docyrus schema from the CLI?
Drive Docyrus platform work from the shell—auth, environments, data records, Studio schema objects, automations, and email—when building or operating a Docyrus-backed app with an agent.
Who is it for?
Developers building on Docyrus who want terminal-driven schema, data, automation, and messaging workflows scripted by an agent.
Skip if: Projects not hosted on Docyrus or teams that only need occasional dashboard clicks without CLI automation.
When should I use this skill?
The user mentions docyrus CLI commands, Studio schema objects, ds records, automations, tenant email, or docyrus tui.
What you get
Authenticated CLI session, updated Studio schema objects, data records, automation graphs, and sent tenant emails.
- Studio schema objects
- Automation workflows
- Sent emails
Files
Docyrus CLI
Guide for using the docyrus CLI (@docyrus/docyrus) to interact with the Docyrus platform from the terminal.
Command Overview
| Command | Description |
|---|---|
docyrus | Show active environment, current auth context, and help summary |
docyrus env list / env use / env which | Manage named environments and inspect resolved settings scope |
docyrus auth login / set-tokens | Authenticate via OAuth2 device flow or manual tokens |
docyrus auth logout / who / tenant | Logout the active account / show active user / show the current tenant record |
docyrus auth accounts list / use | Manage saved user accounts |
docyrus auth tenants list / use | Manage saved tenants for a user |
docyrus auth github / sandbox / sso-session / git-credential | Sandbox/CI token helpers |
docyrus apps list | List apps from /v1/apps |
docyrus apps update / delete / restore / permanent-delete | Mutate apps via /v1/dev/apps/:appId |
docyrus apps set-agent-context | Set an app's AI agent context |
docyrus apps actions ... | CRUD app-scoped actions, list action types, and run an action |
docyrus apps ai-tools ... | CRUD app-scoped AI tools |
docyrus ds get / list | Read data source metadata and query records |
docyrus ds create / update / delete | Mutate records, including bulk create/update |
docyrus ds comments create / files upload | Add a record comment / upload a record file attachment |
docyrus dsql query | Run a read-only logical SQL SELECT over appSlug.dataSourceSlug tables |
docyrus dsql generate / ask | Turn a natural-language question into a DSQL query (and optionally run it) via the DSQL generator agent |
docyrus dsql schema app / data-source / data-sources | Inspect the token-efficient DSQL schema for an app, a data source, or by ids |
docyrus studio ... | CRUD dev app data sources, fields, enums, data views, forms, webforms, HTML/PDF/DOCX templates, email templates; search fields/enums/enum-sets |
docyrus automation ... | CRUD automations, triggers, and action nodes for an app |
docyrus agent ... | CRUD custom AI agents and their sub-resources (models, tools, data-sources, docs, mcps, connections, dynamic-contexts, tasks, recurring-tasks, workflow-steps, deployments, workflow-jobs) |
docyrus messaging accounts / email send | List tenant email accounts / send transactional email |
docyrus connect ... | Discover connectors, inspect actions, send provider-auth requests, run actions |
docyrus discover ... | Download and explore the tenant OpenAPI spec |
docyrus curl | Send arbitrary API requests |
docyrus docy "<prompt>" | Chat with the platform's main AI agent |
docyrus opsy / cody (coder) | Launch the pi Cowork / Coding agents (interactive TUI or one-shot) |
docyrus server | Start the HTTP server bridging a pi agent to AI SDK useChat |
docyrus browser ... | Browser automation (local Chrome or remote Cloudflare) |
docyrus knowledge ... | Repo knowledge-graph search, audit, and maintenance |
docyrus project-plan ... | Repo-tracked project plan graph (phases, features, tasks) |
docyrus release ... | Version bump, changelog, and release record creation |
docyrus tui | Launch the OpenTUI terminal UI (requires Bun) |
See [references/cli-manifest.md](references/cli-manifest.md) for the complete command reference with flags and arguments.
Flag forms:--helpprints flags in kebab-case (--app-slug,--from-file), but the parser also accepts the camelCase schema keys (--appSlug,--fromFile). This guide uses the camelCase form; both work.
Common Workflows
Settings Scope
By default, docyrus stores settings in a project-local .docyrus/ folder in the current working directory.
- Local default:
./.docyrus/ - Global override:
~/.docyrus/via-gor--global - Tenant OpenAPI cache:
<settings-root>/tenans/<tenantId>/openapi.json
# Local project settings (default)
docyrus auth login --clientId "83a8df32-3738-4b5a-a0c7-87976adb1631"
# Force global settings for this run
docyrus -g auth login --clientId "83a8df32-3738-4b5a-a0c7-87976adb1631"
# Inspect which scope/environment is active for this folder
docyrus env which --jsonenv which reports local/global scope, the resolved settingsRoot, configFilePath, authFilePath, cwd, and whether a local .docyrus/ directory exists.
Environments
The CLI does not use API_BASE_URL. It uses saved named environments:
live(prodalias) ->https://api.docyrus.combeta->https://beta-api.docyrus.comalpha->https://alpha-api.docyrus.comdev(local-developmentalias) ->https://localhost:3366
docyrus
docyrus env list --json
docyrus env use beta --jsonRunning docyrus without a subcommand returns the active environment, help summary, and current auth context.
Authentication
Device flow login:
docyrus auth login --clientId "83a8df32-3738-4b5a-a0c7-87976adb1631" --jsonManual token login (auth login or auth set-tokens):
docyrus auth login \
--accessToken "<access-token>" \
--refreshToken "<optional-refresh-token>" \
--clientId "<optional-client-id>" \
--json
docyrus auth set-tokens --accessToken "<access-token>" --refreshToken "<refresh-token>" --jsonRules:
--refreshTokenrequires--accessToken- if local login omits
--clientId, the CLI falls back to the saved global client ID when available - client ID resolution order:
--clientId->DOCYRUS_API_CLIENT_ID-> saved local config -> saved global config ->manual-token(manual auth only) - default scopes are hardcoded:
openid email profile offline_access ReadWrite.All Architect.ReadWrite.All Automations.Run Reports.Run.CustomQuery Messaging.Email.Send Messaging.Sms.Send Messaging.Whatsapp.Send MCP.Connect
Multi-account and multi-tenant workflows:
docyrus auth accounts list --json
docyrus auth accounts use --userId "<user-id>" --json
docyrus auth tenants list --userId "<user-id>" --json
docyrus auth tenants use 1002 --json
docyrus auth tenants use "8d130f7a-4bc4-4be6-a05b-0f8f1b2d93e9" --userId "<user-id>" --json
docyrus auth who --json
docyrus auth tenant --jsonauth tenants use takes a positional tenant selector. Numeric -> tenantNo; otherwise it must be a UUID tenant ID.
auth tenant (singular) returns the active tenant record from GET /v1/tenant/current (id, no, name, account status, product/subscription refs, seats, billing, trial/subscription dates, onboarding status). It is a read-only passthrough like auth who; don't confuse it with the auth tenants (plural) account-management group.
Sandbox / CI token helpers (auth sandbox, auth github, auth sso-session, auth git-credential) inject fresh tokens into a running sandbox app, mint repo-scoped GitHub tokens, or create short-lived SSO sessions for headless browsers. They default --appId to DOCYRUS_SANDBOX_APP_ID and are mostly used by the sandbox runtime rather than by hand.
Successful Result Shape
Every successful command injects a top-level context field:
{
"data": {},
"context": {
"email": "user@example.com",
"tenantName": "Acme",
"tenantNo": 1002,
"tenantDisplay": "Acme (1002)"
}
}If there is no active session, context is null.
Discover API and Entities
Discover commands require an active session. Commands other than discover api auto-download the OpenAPI spec if it is missing locally.
docyrus discover api --json
docyrus discover namespaces --json
docyrus discover path /v1/users --json
docyrus discover endpoint /v1/users/me --json
docyrus discover endpoint [PUT]/v1/users/me/photo --json
docyrus discover entity UserEntity --json
docyrus discover search users,UserEntity --jsonDiscover Data Sources
docyrus apps list --json
docyrus ds get crm contacts --jsonQuery Records (ds list)
Basic listing:
docyrus ds list crm contacts --columns "name, email, phone" --limit 20With filters:
docyrus ds list crm contacts \
--columns "name, email" \
--filters '{"rules":[{"field":"status","operator":"=","value":"active"}]}'With relation expansion:
docyrus ds list crm contacts \
--columns "name, ...related_account(account_name, account_phone)"Keyword filter and date shortcut:
docyrus ds list crm tasks --filterKeyword "renewal"
docyrus ds list crm tasks --filters '{"rules":[{"field":"created_on","operator":"this_month"}]}'ds list also supports the full query engine: --formulas, --calculations, --groupSummaries, --pivot, --childQueries, --expand, --distinctColumns, and --collapseRows.
See [references/list-query-examples.md](references/list-query-examples.md) for columns, filters, sorting, pagination, and advanced (formulas/calculations/pivot/child-query) examples.
Logical SQL (dsql)
dsql query runs a read-only PostgreSQL-compatible SELECT over logical tables named appSlug.dataSourceSlug. The SQL comes from the positional argument, --from-file, or stdin. Use the dsql schema commands first to discover queryable tables and columns.
docyrus dsql schema app base # schema for every data source in an app
docyrus dsql schema data-source base contact # schema for one data source
docyrus dsql schema data-sources --ids ds-1,ds-2 # schema by data source ids
docyrus dsql query "select id, email from base.contact limit 100"
docyrus dsql query --from-file ./report.sqlDon't want to hand-write SQL? Let the DSQL generator agent do it:
docyrus dsql generate "top 10 contacts by revenue this year" # returns the query text only
docyrus dsql ask "how many open tasks are assigned to me?" # generates the query, runs it, returns rowsDSQL is a read-only PostgreSQL subset with a strict function allow-list, logical appSlug.dataSourceSlug tables, tenant.* identity/scope pseudo-functions, and built-in row-level security. See [references/dsql-reference.md](references/dsql-reference.md) for the full capability and limitation reference before writing non-trivial queries.
Record Mutations
Create / update / delete:
docyrus ds create crm contacts --data '{"name":"Jane Doe","email":"jane@example.com"}'
docyrus ds update crm contacts <recordId> --data '{"phone":"+1234567890"}'
docyrus ds delete crm contacts <recordId>Batch and file input:
docyrus ds create crm contacts --data '[{"name":"A"},{"name":"B"}]' --json
docyrus ds update crm contacts --data '[{"id":"1","phone":"+111"},{"id":"2","phone":"+222"}]' --json
docyrus ds create crm contacts --from-file ./contacts-create.csv --json
docyrus ds update crm contacts <recordId> --from-file ./contact-update.json --jsonArray payloads route to bulk endpoints and are limited to 50 items per request.
Record Comments and File Attachments
# Add a comment to a record
docyrus ds comments create crm contacts <recordId> --message "Followed up by phone" --json
docyrus ds comments create crm contacts <recordId> --from-file ./comment.json --json
# Upload a file attachment to a record (multipart/form-data)
docyrus ds files upload crm contacts <recordId> --file ./contract.pdf --json
docyrus ds files upload crm contacts <recordId> --file ./logo.png --publicFile --jsonComment accepts either --message or a full DTO via --data/--from-file. Uploads infer content type from the file extension unless --contentType is set; --publicFile stores in the public tenant bucket.
Studio Schema CRUD (studio)
Use studio for developer-facing schema operations: data sources, fields, enums, saved views, forms, webforms, and export templates. Most data-source-scoped commands accept either --appId/--appSlug and either --dataSourceId/--dataSourceSlug, and the CLI resolves whichever side you did not pass.
# Data sources
docyrus studio list-data-sources --appSlug crm --expand fields --json
docyrus studio get-data-source --appSlug crm --dataSourceSlug contacts --json
docyrus studio create-data-source --appSlug crm --title "Contacts" --name "contacts" --slug "contacts" --json
docyrus studio update-data-source --appId <appId> --dataSourceId <dataSourceId> --data '{"title":"Contacts v2"}' --json
docyrus studio delete-data-source --appId <appId> --dataSourceSlug contacts --json
docyrus studio restore-data-source --appId <appId> --dataSourceId <dataSourceId> --json
docyrus studio permanent-delete-data-source --appId <appId> --dataSourceId <dataSourceId> --json
docyrus studio bulk-create-data-sources --appId <appId> --from-file ./data-sources.json --json
# Fields
docyrus studio list-fields --appSlug crm --dataSourceSlug contacts --json
docyrus studio get-field --appSlug crm --dataSourceSlug contacts --fieldSlug email --json
docyrus studio create-field --appId <appId> --dataSourceId <dataSourceId> --name "Email" --slug "email" --type "text" --json
docyrus studio update-field --appId <appId> --dataSourceId <dataSourceId> --fieldId <fieldId> --data '{"name":"Primary Email"}' --json
docyrus studio delete-field --appId <appId> --dataSourceId <dataSourceId> --fieldSlug email --json
docyrus studio create-fields-batch --appId <appId> --dataSourceId <dataSourceId> --data '[{"name":"Status","slug":"status","type":"text"}]' --json
docyrus studio update-fields-batch --appId <appId> --dataSourceId <dataSourceId> --from-file ./fields-update.json --json
docyrus studio delete-fields-batch --appId <appId> --dataSourceId <dataSourceId> --data '["field-1","field-2"]' --json
# Enums
docyrus studio list-enums --appId <appId> --dataSourceId <dataSourceId> --fieldId <fieldId> --json
docyrus studio create-enums --appId <appId> --dataSourceId <dataSourceId> --fieldId <fieldId> --data '[{"name":"Open","sortOrder":1}]' --json
docyrus studio update-enums --appId <appId> --dataSourceId <dataSourceId> --fieldId <fieldId> --from-file ./enums-update.json --json
docyrus studio delete-enums --appId <appId> --dataSourceId <dataSourceId> --fieldId <fieldId> --data '["enum-1","enum-2"]' --json
# Cross-data-source search (tenant-wide, paged) — useful for discovery/refactors
docyrus studio search-fields --keyword "email" --type "text,email" --json
docyrus studio search-enums --dataSourceId <dataSourceId> --json
docyrus studio search-enum-sets --limit 50 --json
# Data views (/v1/apps/:appSlug/data-sources/:dataSourceSlug/views)
docyrus studio list-data-views --appSlug crm --dataSourceSlug contacts --json
docyrus studio create-data-view --appSlug crm --dataSourceSlug contacts --name "Active customers" \
--filters '{"rules":[{"field":"status","operator":"=","value":"active"}]}' --isDefault --json
docyrus studio update-data-view --appSlug crm --dataSourceSlug contacts --viewId <viewId> --data '{"name":"Renamed view"}' --json
docyrus studio delete-data-view --appSlug crm --dataSourceSlug contacts --viewId <viewId> --json
# Forms (/v1/apps/:appSlug/data-sources/:dataSourceSlug/forms)
docyrus studio create-form --appSlug crm --dataSourceSlug contacts --name "Lead intake" --title "New lead" --json
docyrus studio update-form --appSlug crm --dataSourceSlug contacts --formId <formId> --data '{"title":"Renamed"}' --json
# Webforms (/v1/dev/webforms)
docyrus studio create-webform --appSlug crm --dataSourceSlug contacts --from-file ./contact-webform.json --json
docyrus studio update-webform --webformId <webformId> --data '{"name":"Renamed"}' --json
# HTML / PDF / DOCX export templates (/v1/dev/html-templates)
docyrus studio create-html-template --appSlug crm --dataSourceSlug contacts \
--name "Invoice" --sourceType pdf --pageFormat A4 --pageOrientation portrait \
--body "<h1>{{ company.name }}</h1>" --isDefault --json
# Email templates (/v1/dev/email-templates)
docyrus studio create-email-template --name "Welcome" --subject "Hello {{ user.name }}" --body "<p>Hi</p>" --jsonApp Management (apps)
apps list uses /v1/apps; mutations route through /v1/dev/apps/:appId.
docyrus apps list --json
docyrus apps update --appSlug crm --description "Customer CRM" --color "#2563eb" --json
docyrus apps delete --appId <appId> --json
docyrus apps restore --appId <appId> --json
docyrus apps permanent-delete --appId <appId> --jsonapps update accepts camelCase convenience flags (--name, --slug, --description, --icon, --color, --status, --betaUrl, --chromeExtensionPath, --mobileVersionPath, --agentContext, --routePath) merged over --data/--from-file. Store fields and array/object values must go through --data/--from-file. --status is one of active, design, development, draft, inactive.
App AI Agent Context
Set the freeform AI agent context an app injects into its agents (PATCH /v1/dev/apps/:appId agent_context):
docyrus apps set-agent-context --appSlug crm --value "This app manages B2B sales pipelines." --json
docyrus apps set-agent-context --appSlug crm --from-file ./agent-context.md --json
docyrus apps set-agent-context --appSlug crm --clear --jsonProvide exactly one of --value (inline), --from-file (raw text/markdown), or --clear.
App-Scoped Actions (apps actions)
CRUD over standalone tenant_action rows scoped to an app (/v1/dev/apps/:appId/actions), plus the action-type picker and run:
docyrus apps actions list --appSlug crm --json
docyrus apps actions types --appSlug crm --json # selectable action types (excludes create/update-record + wait-for; color = Tailwind name)
docyrus apps actions get --appSlug crm --actionId <id> --json
docyrus apps actions create --appSlug crm --name "Request barcode" --coreActionId <coreActionId> \
--options '{"shipmentPackageId":987654}' --json
docyrus apps actions update --appSlug crm --actionId <id> --status 2 --json
docyrus apps actions delete --appSlug crm --actionId <id> --json
docyrus apps actions run --appSlug crm --actionId <id> --data '{"foo":"x"}' --json--name and --coreActionId are required on create; --coreActionId is create-only (immutable, rejected on update). Convenience flags cover the common columns; JSON fields (--options, --conditions, --customHeaders, --inputTransformer, --inputTemplate, --inputJsonSchema, --outputJsonSchema, …) are parsed from JSON, and the long tail can go through --data/--from-file. run posts the body as the action input record to the slug-based public endpoint (/v1/apps/:appSlug/actions/:actionId/run); it accepts --appId too (reverse-resolved to the slug).
App-Scoped AI Tools (apps ai-tools)
Full CRUD over tenant_ai_tool rows scoped to an app (/v1/dev/apps/:appId/ai-tools):
docyrus apps ai-tools list --appSlug crm --json
docyrus apps ai-tools get --appSlug crm --toolId <toolId> --json
docyrus apps ai-tools create --appSlug crm --name "Lookup contact" --key lookup_contact \
--type data-source-query --dataSourceQueryDataSourceId <dataSourceId> --json
docyrus apps ai-tools update --appSlug crm --toolId <toolId> --description "Updated" --json
docyrus apps ai-tools delete --appSlug crm --toolId <toolId> --json--name and --key are required on create. Convenience flags cover the common columns; complex/JSON fields (--inputJsonSchema, --outputJsonSchema, --customQueryFilters, --dataSourceQueryColumns, etc.) are parsed from JSON, and the long tail can go through --data/--from-file. Platform-managed fields (group, avatar, restricted, cost, development_status, owner_product_id, core_action_id, core_data_provider_id) are not settable on app-scoped tools.
Automations (automation)
Manage automations, their triggers, and action nodes for an app. All commands route through /v1/dev/apps/:appId/automations. App is resolved with --appId or --appSlug. Automations and nodes have IDs only (no slugs).
# Automation CRUD
docyrus automation list --appSlug crm --json
docyrus automation get --appSlug crm --automationId <automationId> --json
docyrus automation create --appSlug crm \
--name "Notify on new deal" --triggerType recordCreated \
--sourceDataSourceId <dataSourceId> --status 1 --json
docyrus automation update --appSlug crm --automationId <automationId> \
--data '{"name":"Renamed automation","status":1}' --json
docyrus automation delete --appSlug crm --automationId <automationId> --json
# Triggers (typed create/update, type-independent delete)
docyrus automation list-triggers --appSlug crm --automationId <automationId> --json
docyrus automation create-trigger --appSlug crm --automationId <automationId> \
--type record-modified --sourceDataSourceId <dataSourceId> \
--modifiedColumns "status,stage" --modifiedColumnsCondition any --json
docyrus automation create-trigger --appSlug crm --automationId <automationId> \
--type recurrence --recurrenceFrequency day --recurrenceInterval 1 --recurrenceRunAt "09:00" --json
docyrus automation create-trigger --appSlug crm --automationId <automationId> \
--type app-event --dataProviderId <coreDataProviderId> --dataProviderWebhookId <webhookId> --json
docyrus automation update-trigger --appSlug crm --automationId <automationId> \
--type webhook --triggerId <triggerId> --data '{"webhook_name":"renamed"}' --json
docyrus automation delete-trigger --appSlug crm --automationId <automationId> --triggerId <triggerId> --json
# Action nodes (typed create/update, type-independent delete)
docyrus automation list-nodes --appSlug crm --automationId <automationId> --json
docyrus automation create-node --appSlug crm --automationId <automationId> \
--type http-request --requestMethod POST --customEndpoint "https://example.com/webhook" \
--contentType "application/json" --from-file ./http-node.json --json
docyrus automation create-node --appSlug crm --automationId <automationId> \
--type external-action --actionTypeId <coreActionId> --from-file ./external-action.json --json
docyrus automation update-node --appSlug crm --automationId <automationId> \
--type send-email --nodeId <nodeId> --data '{"data":{"to":"user@example.com","subject":"Hi"}}' --json
docyrus automation create-node --appSlug crm --automationId <automationId> \
--type wait-for --name "Wait 2 hours" --parent <previousNodeId> \
--data '{"data":{"delayValue":2,"delayUnit":"hours"}}' --json
docyrus automation delete-node --appSlug crm --automationId <automationId> --nodeId <nodeId> --jsonTrigger --type values (kebab-case URL form): record-created, record-modified, record-deleted, recurrence, app-event, webhook, emailhook, webform, button-activation, manual-activation.
Node --type values (kebab-case URL form): external-action, send-email, send-notification, create-record, update-records, request-approval, request-input, http-request, data-source-query, custom-query, generate-document, ai-prompt, ai-agent, execute-script, wait-for.
Notes:
automation create --triggerTypeuses the camelCase form (recordCreated,recordModified, …) to matchCreateAutomationDto.trigger_type; trigger CRUD commands use kebab-case for--type.- Convenience flags are camelCase on the CLI but converted to
snake_casein the request body. Complex nested objects (triggerdata, nodedata,field_mapping,dynamic_field_mapping,condition,input_template,input_transformer,custom_headers,pre_action_request,post_action_request,target_data_source_condition, …) must be supplied via--data/--from-file.--recurrenceWeekDaysand--modifiedColumnsaccept comma-separated values sent as arrays. app-eventtriggers use--dataProviderIdand--dataProviderWebhookId(obtain viadocyrus connect list-connectors/connect get-connector <slug>);webformtriggers use--webformId.create-node --type external-actionrequires--actionTypeId; the backend validates the supplieddataagainst the linkedcore_action.input_json_schema.create-node --type wait-fortakes no flat flags beyond the common base. Set the delay insidedata: eitherdelaySeconds(integer, capped at 30 days / 2_592_000) or thedelayValue+delayUnit(seconds/minutes/hours/days) pair.
Custom AI Agents (agent)
CRUD for dev-app custom agents and their sub-resources, routed through /v1/dev/apps/:appId/agents.... App is resolved with --appId/--appSlug; the parent agent is --agentId; an individual sub-resource row is --id.
# Agent resource
docyrus agent list --appSlug crm --json
docyrus agent get --appSlug crm --agentId <agentId> --json
docyrus agent create --appSlug crm --skillName "sales_copilot" --name "Sales Copilot" \
--description "Assists with deal updates" --defaultAiModelId <modelId> --supportTools --json
docyrus agent update --appSlug crm --agentId <agentId> --welcomeMessage "Hi!" --json
docyrus agent delete --appSlug crm --agentId <agentId> --json
docyrus agent upload --appSlug crm --agentId <agentId> --column avatar --file ./avatar.png --json
# Sub-resources (each: list / get / create / update / delete, unless noted)
docyrus agent models create --appSlug crm --agentId <agentId> --from-file ./model.json --json
docyrus agent tools create --appSlug crm --agentId <agentId> --coreAiToolId <toolId> --json
docyrus agent data-sources create --appSlug crm --agentId <agentId> --tenantDataSourceId <dataSourceId> --json
docyrus agent docs create --appSlug crm --agentId <agentId> --from-file ./doc.json --json
docyrus agent mcps create --appSlug crm --agentId <agentId> --from-file ./mcp.json --json
docyrus agent connections create --appSlug crm --agentId <agentId> \
--connectedAiAgentId <agentId> --connectionType handoff --json
docyrus agent deployments create --appSlug crm --agentId <agentId> --from-file ./deployment.json --json
docyrus agent workflow-jobs list --appSlug crm --agentId <agentId> --json # read-only (+ get / traces / delete)Sub-resource groups: models, tools, data-sources, docs, mcps, connections, dynamic-contexts, tasks, recurring-tasks, workflow-steps, deployments, deployment-tools (nested under a deployment via --deploymentId; no get), deployment-data-sources (same), and read-only workflow-jobs (list/get/traces/delete).
Notes:
agent createrequires--skillName(the only field required byCreateAgentDto); other sub-resource required fields are enforced by the backend.- Convenience flags map 1:1 onto the matching
Create*Dto/Update*Dtosnake_casekeys; the agent DTO is large, so its flags are a curated subset — the long tail (compaction_*,output_*,prompt_*, …) and any nested arrays go through--data/--from-file. createOnlyfields (e.g.--tenantDataSourceId, agent-tool--coreAiToolId) appear only oncreate;updateOnlyfields (e.g.--archived) only onupdate. incur rejects unknown flags, so passing the wrong one fails before any request.deletereturns a{ deleted: true, id }envelope.
Messaging (messaging)
List tenant email accounts and send transactional emails. Routes through /v1/messaging/email/*. Requires the Messaging.Email.Send OAuth2 scope.
docyrus messaging accounts --json
docyrus messaging email send \
--accountId <accountUuid> \
--to "ops@example.com,sales@example.com" \
--subject "Daily summary" \
--body "<p>Hello</p>" --json
docyrus messaging email send --accountId <accountUuid> \
--to "user@example.com" --cc "manager@example.com" --replyTo "support@example.com" --sendAsUser \
--subject "Update" --body "<p>...</p>" --json
docyrus messaging email send --accountId <accountUuid> --from-file ./send.json --jsonLimits: up to 50 recipients per to/cc/bcc/replyTo, subject max 998 chars, body max 1 000 000 chars, up to 10 attachments. Attachment filePath references a tenant-scoped storage path. The response contains messageId, provider, accepted, and rejected.
Connectors and Actions (connect)
Connectors are external integration providers (e.g. Meta WhatsApp, Microsoft Graph, Salesforce). Use connect to find connectors, inspect data sources/actions, check connection status, send provider-auth requests, and run actions.
# Discovery
docyrus connect list-connectors --q whatsapp --json
docyrus connect get-connector meta-whatsapp --json
docyrus connect get-action meta-whatsapp sendWhatsappMessage --json
docyrus connect list-connections meta-whatsapp --json
# Send requests through connector auth (OAuth tokens, base URL, API keys)
docyrus connect curl meta-whatsapp "433457363182570/phone_numbers" \
-d '{"fields":"id,display_phone_number,verified_name"}' --json
docyrus connect curl meta-whatsapp "418088118057836/messages" -X POST \
-d '{"messaging_product":"whatsapp","to":"905551234567","type":"template","template":{"name":"sample_template","language":{"code":"en_US"}}}' \
--contentType "application/json" --json
# Run a connector action directly by provider slug + action key (POST /v1/connectors/:slug/actions/:actionKey/run)
docyrus connect run-action meta-whatsapp sendWhatsappMessage --params '{"to":"905551234567","templateName":"hello_world"}' --json
docyrus connect run-action meta-whatsapp sendWhatsappMessage --params '{"to":"905551234567"}' --dryRun --jsonAliases: connect curl — -X (method), -d (data), -c (connectionId). connect run-action — -p (params), -c (connectionId), -n (dryRun). connect curl data is sent as body for POST/PUT/PATCH and as query params for GET; --headers can override the Authorization header.
Arbitrary API Calls
docyrus curl /v1/users/me
docyrus curl /v1/apps -X GET --format json
docyrus curl /v1/some/endpoint -X POST -d '{"key":"value"}'AI Agents and Dev Tooling
Beyond data operations, the CLI bundles the pi agent runtime and repo dev tooling. These are largely interactive or sandbox-runtime commands.
Chat and pi Agents
docyrus docy "Summarize open deals this month" # one prompt to the platform's main AI agent
docyrus opsy # launch the Cowork Agent (interactive TUI)
docyrus cody "fix the failing test in ds list" # launch the Coding Agent (coder is an alias)
docyrus cody --print --mode json "list TODOs" # one-shot, machine outputdocy sends a single prompt (--agentId/--deploymentId optional); it renders markdown in a TTY and structured output with --json/--verbose/--format. opsy/cody/coder open the pi TUI by default, or run one-shot with --print; they accept --provider, --model, --thinking, --continue, --resume, --session, --apiKey, etc.
Agent Server
docyrus server --profile coder --port 3111Starts an HTTP server bridging a pi agent to the AI SDK useChat protocol (SSE chat stream with reconnect/resume). Flags include --auth (require a bearer token), --sandbox (remote Cloudflare browser mode), and --desktop (expose docyrus_browser_* tools).
Browser Automation
docyrus browser start --profile
docyrus browser nav https://example.com
docyrus browser snapshot # compact element refs (@e1 …) for interaction
docyrus browser click @e3
docyrus browser fill @e5 "hello"
docyrus browser screenshot --full
docyrus browser content https://example.com # extract readable markdown
docyrus browser closeRuns against local Chrome (:9222) or a remote Cloudflare session. Other subcommands: eval, select, wait, tabs, cookies, console, network, info, devtools, run-script.
Repo Knowledge Graph and Project Plan
docyrus knowledge search "how does auth refresh work"
docyrus knowledge section <sectionId>
docyrus knowledge check # validate links/backlinks
docyrus project-plan show
docyrus project-plan list-tasks --status in_progress --limit 5
docyrus project-plan set-task-status --taskId <id> --status doneknowledge manages the repo's docyrus/knowledge graph (search, audit, refresh, pre-commit gates). project-plan manages a repo-tracked plan graph of phases, features, and tasks (token-efficient list/find/upsert/status commands). Both are local dev-workflow tools used by the pi agents.
Releases
docyrus release status
docyrus release new-version --bump minor --json
docyrus release new-version --version 1.2.0 --dryRun --jsonBumps the version, generates a changelog, optionally tags, creates a GitHub release, and records a DB release row (skip with --skip* flags).
Terminal UI
docyrus tuiLaunches the OpenTUI interface (requires Bun). It reuses the existing CLI command graph.
Key Rules
- Settings are project-local by default in
./.docyrus/; use-g/--globalfor~/.docyrus/.env whichshows the resolved scope. - The CLI uses named environments, not
API_BASE_URL. - Flags accept both kebab-case (
--app-slug, as--helpprints) and camelCase (--appSlug, the schema key).--from-filereads JSON (and CSV fords). - Default login scopes are
openid email profile offline_access ReadWrite.All Architect.ReadWrite.All Automations.Run Reports.Run.CustomQuery Messaging.Email.Send Messaging.Sms.Send Messaging.Whatsapp.Send MCP.Connect. - Successful responses inject
context(email,tenantName,tenantNo,tenantDisplay); it isnullwith no active session. apps listuses/v1/apps;appsmutations andset-agent-context/ai-toolsuse/v1/dev/apps/:appId.dscommands useappSluganddataSourceSlug.ds create/updateaccept--dataJSON or--from-file(.json/.csv), not both. Array payloads use bulk endpoints (max 50); bulk update requiresidin each item and no positional<recordId>.ds listsupports--columns(relation(), spread..., alias:, function@),--filters(JSON filter group),--filterKeyword,--orderBy,--formulas,--calculations,--groupSummaries,--pivot,--childQueries,--expand,--distinctColumns,--collapseRows,--limit,--offset,--fullCount. Related-field filters userel_<relation_slug>/<field_slug>.--formatsupportstoon,json,yaml,md, andjsonl.- Studio selectors are exclusive pairs: exactly one of
--appId|--appSlug,--dataSourceId|--dataSourceSlug, and--fieldId|--fieldSlugas required. Studio write commands accept--dataor--from-file(JSON only); explicit flags override overlapping JSON keys.restore-data-source/permanent-delete-data-sourcerequire--dataSourceId. - Studio data-view/form commands route through
/v1/apps/:appSlug/data-sources/:dataSourceSlug/...; webform/html-template/email-template commands route through/v1/dev/webforms,/v1/dev/html-templates,/v1/dev/email-templates(CRUD by--webformId/--templateId). automationroutes through/v1/dev/apps/:appId/automations; trigger/nodecreate/updateuse typed URLs (/triggers/<type>,/nodes/<type>), butdelete-trigger/delete-nodeuse the type-independent route. CLI flags are camelCase, converted tosnake_case; nested objects go through--data/--from-file.automation create --triggerTypeis camelCase; trigger/node--typeis kebab-case.agentcommands route through/v1/dev/apps/:appId/agents...; the parent agent is--agentIdand a sub-resource row is--id.agent createrequires--skillName.createOnly/updateOnlyflags are filtered per command.messagingroutes through/v1/messaging/email/*and needsMessaging.Email.Send;accountsnever returns credentials.connectuses the/v1/connectorsAPI;connect curlsends through provider auth;connect run-action <providerSlug> <actionKey>is connector-scoped (POST /v1/connectors/:slug/actions/:actionKey/run). To run a persisted app action instead, useapps actions run(POST /v1/apps/:appSlug/actions/:actionId/run).tuirequires Bun;docy/opsy/cody/coder/serverrun the pi agent runtime;knowledge/project-plan/releaseare repo dev-workflow tools.
References
- [CLI Manifest](references/cli-manifest.md) — Complete command reference with flags, arguments, and command notes.
- [List Query Examples](references/list-query-examples.md) — Practical
ds listexamples covering columns, filters, sorting, pagination, and advanced queries. - [DSQL Reference](references/dsql-reference.md) — Logical SQL (
dsql query) capabilities and limits: table naming, allowed functions,tenant.*pseudo-functions, casts, row limits, access control, and the error catalog.
Docyrus CLI Manifest
LLM-ready reference for the docyrus CLI tool (@docyrus/docyrus). Generated from the live command graph (docyrus --llms).
---
Global Options
| Flag | Type | Description |
|---|---|---|
-g, --global | boolean | Force global ~/.docyrus/ settings instead of local ./.docyrus/ |
| `--format <toon\ | json\ | yaml\ |
--help | boolean | Show help (prints flags in kebab-case) |
--llms | boolean | Print the full LLM-readable manifest |
--mcp | boolean | Start as an MCP stdio server |
--verbose | boolean | Show full output envelope |
--version | boolean | Show version |
Flag forms: --help prints flags in kebab-case (--app-slug, --from-file); the parser also accepts the camelCase schema keys (--appSlug, --fromFile). Both forms work. This manifest uses camelCase.
Environment Variables
| Name | Description |
|---|---|
DOCYRUS_API_CLIENT_ID | Default Docyrus OAuth2 client id |
DOCYRUS_SANDBOX_APP_ID | Active sandbox app id (injected by the sandbox runtime; default for --appId on sandbox/release commands) |
Settings Scope
- Default scope is local:
./.docyrus/ - Use
-g/--globalfor global scope:~/.docyrus/ - Auth state:
<settings-root>/auth.json - Environment config:
<settings-root>/config.json - OpenAPI cache:
<settings-root>/tenans/<tenantId>/openapi.json docyruswithout a subcommand returns active environment, help commands, and authcontext
Output Model
Every successful command injects a top-level context object (email, tenantName, tenantNo, tenantDisplay); it is null when there is no active session. Object payloads are merged with context; non-object payloads become { data, context }.
---
docyrus env
Environment commands.
docyrus env list
List available environments.
docyrus env use
Switch active environment by id or name.
docyrus env use <selector>| Argument | Type | Required | Description |
|---|---|---|---|
selector | string | yes | Environment id or name (live, prod, beta, alpha, dev, local-development) |
Built-in environments:
live(prodalias) ->https://api.docyrus.combeta->https://beta-api.docyrus.comalpha->https://alpha-api.docyrus.comdev(local-developmentalias) ->https://localhost:3366
docyrus env which
Show which environment is active for the current folder, plus the resolved settings scope (local/global), settingsRoot, configFilePath, authFilePath, cwd, and whether a local .docyrus/ exists.
---
docyrus auth
Authentication commands.
docyrus auth login
Authorize CLI using OAuth2 device flow, or provide tokens manually.
| Flag | Type | Description |
|---|---|---|
--clientId | string | OAuth2 client id |
--scope | string | OAuth2 scopes (default below) |
--accessToken | string | Manual access token; skips device flow |
--refreshToken | string | Manual refresh token; requires --accessToken |
Default scope: openid email profile offline_access ReadWrite.All Architect.ReadWrite.All Automations.Run Reports.Run.CustomQuery Messaging.Email.Send Messaging.Sms.Send Messaging.Whatsapp.Send MCP.Connect
Login notes:
- Client ID resolution order:
--clientId->DOCYRUS_API_CLIENT_ID-> saved local config -> saved global config ->manual-token(manual-token auth only) - Manual token login falls back to
manual-tokenonly when no client ID can be resolved - Local login can reuse the globally saved client ID when local config has none
docyrus auth set-tokens
Set custom access and refresh tokens for the active environment. Same flags as auth login (--clientId, --scope, --accessToken, --refreshToken).
docyrus auth logout
Revoke and clear all tenant sessions for the active account in the current environment.
| Flag | Type | Description |
|---|---|---|
--clientId | string | OAuth2 client id override |
docyrus auth who
Return the current authenticated user (/v1/users/me).
docyrus auth tenant
Return the active tenant record (GET /v1/tenant/current). Read-only; no flags. Returns id, no, name, accountStatus, product/subscription refs, seat counts, paymentChannel, trial and subscription dates, and onboardingStatus. Distinct from the auth tenants (plural) account-management group.
docyrus auth accounts list
List saved user accounts for the current API base URL.
docyrus auth accounts use
Switch active account by user ID.
| Flag | Type | Description |
|---|---|---|
--userId | string | User ID to activate |
docyrus auth tenants list
List available tenants for an account.
| Flag | Type | Description |
|---|---|---|
--userId | string | User ID; defaults to active account |
docyrus auth tenants use
Switch active tenant for an account.
docyrus auth tenants use <tenantSelector> [options]| Argument | Type | Required | Description |
|---|---|---|---|
tenantSelector | string | yes | Numeric tenant no or UUID tenant id |
| Flag | Type | Description |
|---|---|---|
--userId | string | User ID; defaults to active account |
--scope | string | Scope used only when tenant bootstrap login is required |
Selector rules: numeric -> match by tenantNo; non-numeric must be a UUID tenant id.
Sandbox / CI token helpers
Mostly invoked by the sandbox runtime; all default --appId to DOCYRUS_SANDBOX_APP_ID.
| Command | Description | Key flags |
|---|---|---|
docyrus auth sandbox | Refresh and inject fresh auth tokens into the active sandbox | --appId |
docyrus auth github | Regenerate the GitHub token and inject it into the active sandbox | --appId, --cwd |
docyrus auth git-credential | Git credential helper supplying a repo-scoped GitHub token | --operation, --appId |
docyrus auth sso-session | Create a short-lived SSO session token for headless browser auth | --clientId, --scope, --targetOrigin |
---
docyrus apps
App commands. list uses /v1/apps; mutations and AI sub-resources route through /v1/dev/apps/:appId. --appSlug resolution first consults the bundled SYSTEM/APP catalog, then falls back to GET /v1/apps.
docyrus apps list
List apps (/v1/apps).
| Flag | Type | Description |
|---|---|---|
--appType | string | Optional app type filter |
--noCache | boolean | Bypass the server cache and read all apps directly from the database |
docyrus apps update
PATCH /dev/apps/:appId. Store fields and array/object values must be supplied via --data/--from-file. An empty resulting payload is rejected.
| Flag | Type | Description |
|---|---|---|
--appId / --appSlug | string | App selector |
--data / --from-file | string | JSON payload / file |
--name | string | App name |
--slug | string | New app slug |
--description | string | App description |
--icon | string | App icon |
--color | string | App color |
--status | string | App status (active, design, development, draft, inactive) |
--betaUrl | string | Beta URL |
--chromeExtensionPath | string | Chrome extension path |
--mobileVersionPath | string | Mobile version path |
--agentContext | string | Agent context |
--routePath | string | Route path under the shared repo host (e.g. /crm) |
docyrus apps set-agent-context
PATCH /dev/apps/:appId (agent_context). Provide exactly one of --value, --from-file, or --clear.
| Flag | Type | Description |
|---|---|---|
--appId / --appSlug | string | App selector |
--value | string | Agent context value (inline) |
--from-file | string | Path to a text/markdown file holding the value |
--clear | boolean | Clear the agent context (set to empty string) |
docyrus apps delete / restore / permanent-delete
Archive / restore / hard-delete an app.
| Flag | Type | Description |
|---|---|---|
--appId / --appSlug | string | App selector |
docyrus apps ai-tools
CRUD over app-scoped tenant_ai_tool rows (/dev/apps/:appId/ai-tools). All commands take --appId/--appSlug.
list— list AI tools for an appget/delete—--toolIdcreate—--nameand--keyrequiredupdate—--toolIdplus changed fields
Create/update convenience flags: --name, --key, --description, --icon, --type, --clientSideExecution, --needsApproval, --environments (CSV), --dynamicApprovalFormula, --inputJsonSchema (JSON), --outputJsonSchema (JSON), --secureExecCode, --customQuerySqlQuery, --customQueryFilters (JSON), --dataSourceQueryDataSourceId, --dataSourceQueryColumns (JSON), --dataSourceQueryFilters (JSON), --dataSourceQueryFilterKeyword, --dataSourceQueryFormulas (JSON), --dataSourceQueryChildQueries (JSON), --dataSourceQueryLimit, plus --data/--from-file.
Platform-managed fields (group, avatar, restricted, cost, development_status, owner_product_id, core_action_id, core_data_provider_id) are not settable on app-scoped tools — the endpoint leaves them at their defaults.
docyrus apps actions
CRUD over standalone tenant_action rows (/dev/apps/:appId/actions), plus the action-type picker and run. All commands take --appId/--appSlug.
list— list app actionstypes— list selectable action types (/dev/apps/:appId/actions/types); excludes client-only and automation-flow-only actions (create/update record, wait-for); each row carriescolor(Tailwind color name)get/delete—--actionIdcreate—--nameand--coreActionIdrequired (--coreActionIdis create-only / immutable)update—--actionIdplus changed fields (--coreActionIdis rejected)run—--actionId; posts the body as the action input record to the slug-based public endpointPOST /v1/apps/:appSlug/actions/:actionId/run(accepts--appId, reverse-resolved to the slug); body via--data/--from-file(an empty body is allowed)
Create/update convenience flags: --name, --coreActionId (create only), --status, --options (JSON), --conditions (JSON), --sourceDataSourceId, --inputDataSourceId, --targetDataSourceId, --targetDataSourceFieldId, --targetDataSourceCondition (JSON), --connectionId, --connectionAccountId, --webhookId, --requestMethod, --contentType, --customEndpoint, --relativeEndpoint, --batch, --batchSize, --customHeaders (JSON), --inputTransformer (JSON), --outputTransformer, --batchTransformer, --errorTransformer, --inputTemplate (JSON), --preActionRequest (JSON), --postActionRequest (JSON), --inputJsonSchema (JSON), --outputJsonSchema (JSON), plus --data/--from-file.
---
docyrus ds
Data source commands for CRUD on records.
docyrus ds get
Get data source metadata (fields, types, relations).
docyrus ds get <appSlug> <dataSourceSlug>docyrus ds list
List data source items with the full query engine.
docyrus ds list <appSlug> <dataSourceSlug> [options]| Flag | Type | Description |
|---|---|---|
--columns | string | Columns to select; comma-separated or JSON array (supports relation (), spread ..., alias :, function @) |
--distinctColumns | string | Distinct columns; comma-separated or JSON array |
--filters | string | JSON filter group ({"combinator":"and","rules":[...]}) |
--filterKeyword | string | Full-text keyword filter |
--orderBy | string | Sort order string or JSON object/array |
--limit | number | Max records |
--offset | number | Skip N records |
--fullCount | boolean | Include total count |
--formulas | string | JSON formulas object |
--calculations | string | JSON calculations array |
--groupSummaries | boolean | Return per-group summaries when calculations are used |
--collapseRows | boolean | Collapse rows into a single aggregated array |
--expand | string | Expand columns; comma-separated or JSON array |
--pivot | string | JSON pivot configuration |
--childQueries | string | JSON child query array |
docyrus ds create
Create item(s). Array payload triggers POST /apps/:appSlug/data-sources/:dataSourceSlug/items/bulk (max 50 items).
docyrus ds create <appSlug> <dataSourceSlug> [options]| Flag | Type | Description |
|---|---|---|
--data | string | JSON payload for record fields |
--from-file | string | Path to a .json or .csv payload file |
docyrus ds update
Update item(s). Object payload uses the single-item endpoint and requires recordId; array payload uses the bulk endpoint, requires id in each item, and must not include positional recordId. Max 50 per batch.
docyrus ds update <appSlug> <dataSourceSlug> [recordId] [options]| Flag | Type | Description |
|---|---|---|
--data | string | JSON payload for record fields |
--from-file | string | Path to a .json or .csv payload file |
docyrus ds delete
Delete an item.
docyrus ds delete <appSlug> <dataSourceSlug> <recordId>docyrus ds comments create
Create a record-scoped comment.
docyrus ds comments create <appSlug> <dataSourceSlug> <recordId> [options]| Flag | Type | Description |
|---|---|---|
--message | string | Comment message |
--data / --from-file | string | Full comment DTO as JSON / file |
--parentId | string | Parent comment ID |
--assignedTo | string | Assigned user ID |
--attachments | string | JSON attachments payload |
--level | number | Comment level |
--status | number | Comment status |
--done | boolean | Mark comment as done |
docyrus ds files upload
Upload a record-scoped file attachment (multipart/form-data).
docyrus ds files upload <appSlug> <dataSourceSlug> <recordId> [options]| Flag | Type | Description |
|---|---|---|
--file | string | Path to the local file |
--contentType | string | Override the inferred MIME type |
--publicFile | boolean | Store the file in the public tenant bucket |
---
docyrus dsql
Run read-only logical SQL queries and inspect the token-efficient DSQL schema. Logical tables are named appSlug.dataSourceSlug (e.g. base.contact). Requires DS.Read.* / DS.ReadWrite.* scopes.
docyrus dsql query
Run a read-only PostgreSQL-compatible SELECT over logical data-source tables (PUT /dsql/query). The SQL is resolved from the positional argument, --from-file, or stdin (in that order). Throttled to 60 requests/minute.
docyrus dsql query "select id, email from base.contact limit 100"
docyrus dsql query --from-file ./report.sql
echo "select count(*) from base.task" | docyrus dsql query| Flag | Type | Description |
|---|---|---|
--from-file | string | Path to a file containing the SQL query |
Returns { data: [...], meta: { count } }.
docyrus dsql generate
Generate a DSQL query from a natural-language question using the base DSQL generator agent (POST /ai/agents/:agentId/chat). Returns the query text only — it does not run it. The question is resolved from the positional argument, --from-file, or stdin.
docyrus dsql generate "top 10 contacts by revenue this year"
docyrus dsql generate --from-file ./question.txt| Flag | Type | Description |
|---|---|---|
--from-file | string | Path to a file containing the question |
--agentId | string | Override the default DSQL generator agent id |
--deploymentId | string | Optional agent deployment id |
The agent returns structured output: { prompt, query } (it echoes a normalized prompt alongside the generated query).
docyrus dsql ask
Generate a DSQL query from a natural-language question, then run it through PUT /dsql/query and return the rows. Combines generate + query.
docyrus dsql ask "how many open tasks are assigned to me?"| Flag | Type | Description |
|---|---|---|
--from-file | string | Path to a file containing the question |
--agentId | string | Override the default DSQL generator agent id |
--deploymentId | string | Optional agent deployment id |
Returns { prompt, query, data: [...], meta: { count } }.
docyrus dsql schema app
Return the DSQL schema for every queryable data source in an app (GET /dsql/schema/apps/:appSlug).
docyrus dsql schema app basedocyrus dsql schema data-source
Return the DSQL schema for a single data source (GET /dsql/schema/apps/:appSlug/data-sources/:dataSourceSlug).
docyrus dsql schema data-source base contactdocyrus dsql schema data-sources
Return the DSQL schema for the data sources matching the given ids (GET /dsql/schema/data-sources?ids=...).
docyrus dsql schema data-sources --ids ds-1,ds-2| Flag | Type | Description |
|---|---|---|
--ids | string | Comma-separated data source ids (required) |
---
docyrus studio
Dev-app schema CRUD. Data-source/field commands route through /v1/dev/apps/:appId/data-sources...; data-view/form commands route through /v1/apps/:appSlug/data-sources/:dataSourceSlug/...; webform/html-template/email-template commands route through /v1/dev/webforms, /v1/dev/html-templates, /v1/dev/email-templates.
Selector rules:
- app selector: exactly one of
--appIdor--appSlug - data source selector: exactly one of
--dataSourceIdor--dataSourceSlugwhen required - field selector: exactly one of
--fieldIdor--fieldSlugwhen required
Write payload rules:
- use
--data '<json>'or--from-file ./payload.json(JSON only), not both - flags override conflicting keys from the JSON payload
- batch commands accept a root array or a root object containing the expected DTO key
Data source commands
| Command | Route | Notes |
|---|---|---|
list-data-sources | GET /dev/apps/:app/data-sources | --expand fields |
get-data-source | GET .../:id | app + data source selector |
create-data-source | POST .../data-sources | --title, --name, --slug, --type, --icon, --dataSharing, --meta (JSON) |
update-data-source | PATCH .../:id | create flags + data source selector |
delete-data-source | DELETE .../:id | archives the data source |
restore-data-source | restore | requires --dataSourceId (slug unavailable for archived rows) |
permanent-delete-data-source | hard delete | requires --dataSourceId |
bulk-create-data-sources | POST .../bulk | DTO key dataSources |
Field commands
| Command | Route | Notes |
|---|---|---|
list-fields | GET .../:ds/fields | app + data source selector |
get-field | GET .../fields/:id | + field selector |
create-field | POST .../fields | --name, --slug, --type, --readOnly, --status, --defaultValue, --relationDataSourceId, --sortOrder, --tenantEnumSetId, --options (JSON), --validations (JSON) |
update-field | PATCH .../fields/:id | create flags + field selector |
delete-field | DELETE .../fields/:id | app + data source + field selector |
create-fields-batch | POST .../fields/batch | DTO key fields |
update-fields-batch | PATCH .../fields/batch | DTO key fields; backend expects fields[].fieldId |
delete-fields-batch | DELETE .../fields/batch | DTO key fieldIds |
The CLI normalizes common live-output shapes before sending batches: id -> fieldId, id -> enumId, read_only -> readOnly, default_value -> defaultValue, relation_data_source_id -> relationDataSourceId, options -> editorOptions.
Enum commands
| Command | Route | DTO key |
|---|---|---|
list-enums | GET .../fields/:id/enums | — |
create-enums | POST .../fields/:id/enums | enums |
update-enums | PATCH .../fields/:id/enums | enums (backend expects enums[].enumId) |
delete-enums | DELETE .../fields/:id/enums | enumIds |
Search commands (tenant-wide, paged)
| Command | Description | Flags |
|---|---|---|
search-fields | Search fields across all data sources | --dataSourceId (CSV), --type (CSV), --keyword, --limit, --offset |
search-enums | Search enums across data sources, fields, and enum sets | --dataSourceId, --enumSetId, --fieldId, --limit, --offset |
search-enum-sets | Search enum sets | --limit, --offset |
Data view commands
Route through /v1/apps/:appSlug/data-sources/:dataSourceSlug/views. Pass either --appId/--appSlug and either --dataSourceId/--dataSourceSlug; the CLI resolves the missing side.
| Command | Route | Notes |
|---|---|---|
list-data-views | GET .../views | --tenantAppId optional |
get-data-view | GET .../views/:viewId | --viewId required |
create-data-view | POST .../views | --name, --description, --tenantAppId, --columns (JSON), --filters (JSON), --sort (JSON), --color, --icon, --colorRules (JSON), --quickFilterFields (JSON), --isDefault, --sortOrder |
update-data-view | PUT .../views/:viewId | create flags + --viewId, --archived |
delete-data-view | DELETE .../views/:viewId | --viewId required |
Form commands
Route through /v1/apps/:appSlug/data-sources/:dataSourceSlug/forms.
| Command | Route | Notes |
|---|---|---|
list-forms | GET .../forms | — |
get-form | GET .../forms/:formId | --formId required |
create-form | POST .../forms | --name, --description, --title, --subtopic, --color, --icon, --layout (JSON), --isDefault, --status |
update-form | PUT .../forms/:formId | create flags + --formId, --archived |
delete-form | DELETE .../forms/:formId | --formId required |
Webform commands
Route through /v1/dev/webforms. CRUD by --webformId. List/create accept --dataSourceId, or --dataSourceSlug with --appId/--appSlug to resolve. When dataSourceId is omitted on create, submissions land in the tenant-schema webform_record table.
| Command | Route | Notes |
|---|---|---|
list-webforms | GET /dev/webforms | optional data source filter |
get-webform | GET /dev/webforms/:id | --webformId |
create-webform | POST /dev/webforms | --name, --schema (JSON), --status (1 active, 2 inactive), --webformOptions (JSON), --sandbox, --css |
update-webform | PATCH /dev/webforms/:id | --webformId + same fields |
delete-webform | DELETE /dev/webforms/:id | --webformId |
HTML template commands (HTML / PDF / DOCX export)
Route through /v1/dev/html-templates. CRUD by --templateId. Data source binding by --dataSourceId or --dataSourceSlug (slug requires --appId/--appSlug).
| Command | Route | Notes |
|---|---|---|
list-html-templates | GET /dev/html-templates | --isDefault, --limit, --offset |
get-html-template | GET /dev/html-templates/:id | --templateId |
create-html-template | POST /dev/html-templates | --name, --filenameTmpl, --pageOrientation, --sourceType (html/pdf/docx), --marginLeft/Right/Top/Bottom, --pageFormat (A4/Letter), --body, --isDefault, --headerTmpl, --footerTmpl, --styles |
update-html-template | PUT /dev/html-templates/:id | create flags + --templateId |
delete-html-template | DELETE /dev/html-templates/:id | --templateId |
Email template commands
Route through /v1/dev/email-templates. CRUD by --templateId. Data source binding optional.
| Command | Route | Notes |
|---|---|---|
list-email-templates | GET /dev/email-templates | --limit, --offset |
get-email-template | GET /dev/email-templates/:id | --templateId |
create-email-template | POST /dev/email-templates | --name, --subject, --body, --ownership (system/user) |
update-email-template | PUT /dev/email-templates/:id | create flags + --templateId |
delete-email-template | DELETE /dev/email-templates/:id | --templateId |
---
docyrus automation
Automation, trigger, and action node CRUD. Routes through /v1/dev/apps/:appId/automations.
Selector rules:
- app selector: exactly one of
--appIdor--appSlug - automation selector:
--automationIdonly (no slug) - trigger
--type(kebab-case):record-created,record-modified,record-deleted,recurrence,app-event,webhook,emailhook,webform,button-activation,manual-activation - node
--type(kebab-case):external-action,send-email,send-notification,create-record,update-records,request-approval,request-input,http-request,data-source-query,custom-query,generate-document,ai-prompt,ai-agent,execute-script,wait-for
Write payload rules:
- write commands accept
--data '<json>'or--from-file ./payload.json(JSON only) - convenience flags are camelCase and converted to
snake_case - nested objects (
data,field_mapping,dynamic_field_mapping,condition,input_template,input_transformer,custom_headers,pre_action_request,post_action_request,target_data_source_condition) must be supplied via--data/--from-file delete,delete-trigger,delete-nodereturn{ deleted: true, id }(API returns 204)
Automation CRUD
| Command | Route | Notes |
|---|---|---|
list | GET .../automations | app selector |
get | GET .../automations/:id | --automationId |
create | POST .../automations | --name, --triggerType (camelCase: recordCreated, recordModified, recordDeleted, recurrence, appEvent, webhook, emailhook, webform, buttonActivation, manualActivation), --status, --sourceDataSourceId, --triggerDataSourceId, --triggerDataProviderId, --triggerWebhookId |
update | PATCH .../automations/:id | --automationId, --name, --status, --sourceDataSourceId |
delete | DELETE .../automations/:id | --automationId |
Trigger commands
list-triggers / get-trigger are derived from the automation GET response. create-trigger/update-trigger route through POST|PATCH .../triggers/:type[/ :triggerId]; delete-trigger routes through DELETE .../triggers/:triggerId (type-independent).
create-trigger flags (--automationId, --type required):
| Flag | Type | Description |
|---|---|---|
--active | boolean | Whether the trigger is active |
--sourceDataSourceId | string | Source data source (record-*, recurrence, button/manual) |
--maxRunPerRecord | number | Max runs per record (record-*, recurrence) |
--modifiedColumns | string | Comma-separated modified columns (record-modified) |
--modifiedColumnsCondition | string | all or any (record-modified) |
--recurrenceFrequency | string | hour, day, week, month, year (recurrence) |
--recurrenceInterval | number | Recurrence interval (recurrence) |
--recurrenceMinutes | number | Minutes `0\ |
--recurrenceWeekDays | string | Comma-separated MON,TUE,... (recurrence) |
--recurrenceMonthDays | string | DAY_OF_MONTH or DAY_OF_WEEK (recurrence) |
--recurrenceStartDate / --recurrenceEndDate | string | ISO date (recurrence) |
--recurrenceRunAt | string | HH:mm (recurrence) |
--dataProviderId | string | Data provider id, a.k.a. connector (app-event); obtain via docyrus connect list-connectors |
--dataProviderWebhookId | string | Data provider webhook id (app-event); obtain via docyrus connect get-connector <slug> |
--webhookId | string | Webhook id (webhook, emailhook) |
--webhookName | string | Name for auto-created webhook (webhook, emailhook) |
--webformId | string | Webform id (webform) |
--data / --from-file | string | JSON payload / file |
update-trigger adds --triggerId (required). delete-trigger takes --automationId and --triggerId.
Action node commands
list-nodes (GET .../nodes), get-node (GET .../nodes/:nodeId). create-node/update-node route through POST|PATCH .../nodes/:type[/ :nodeId]; delete-node routes through DELETE .../nodes/:nodeId (type-independent).
create-node flags (--automationId, --type required):
| Flag | Type | Description |
|---|---|---|
--name / --description | string | Node name / description |
--subType | string | Sub type discriminator |
--parent | string | Parent node id |
--active | boolean | Whether the node is active |
--actionTypeId | string | Action type id (required for external-action; maps to core_action.id) |
--sourceDataSourceId | string | Source data source id (external-action) |
--targetDataSourceId | string | Target data source id (create-record, update-records, http-request, data-source-query, external-action) |
--targetDataSourceFieldId | string | Target field id (update-records) |
--connectionId / --connectionAccountId | string | Connection (http-request, external-action) |
--webhookId | string | Webhook id (external-action) |
--inputDataSourceId | string | Input data source id (request-approval, request-input) |
--requestMethod | string | HTTP method (http-request) |
--contentType | string | HTTP content type (http-request) |
--customEndpoint | string | HTTP endpoint (http-request) |
--relativeEndpoint | boolean | Endpoint relative to connection base url (http-request) |
--batch / --batchSize | boolean / number | HTTP batching 1..10000 (http-request) |
--outputTransformer / --batchTransformer / --errorTransformer | string | Transformer expressions (http-request) |
--data / --from-file | string | JSON payload / file |
update-node adds --nodeId (required). delete-node takes --automationId and --nodeId.
Notes:
external-actioncreate validatesdataagainst the linkedcore_action.input_json_schemaand creates thetenant_actionrow in the same transaction.wait-fortakes no flat flags beyond the common base. Set the delay insidedata:delaySeconds(integer ≤ 30 days / 2_592_000) ordelayValue+delayUnit(seconds/minutes/hours/days). It forwards input unchanged and queues next step(s) with a deferredtenant_job_queue.process_after.
docyrus automation create-node \
--appSlug crm --automationId 9c4f… \
--type wait-for --name "Wait 2 hours" --parent <previous-node-id> \
--data '{"data":{"delayValue":2,"delayUnit":"hours"}}'---
docyrus agent
Custom-agent CRUD for the dev controller (/v1/dev/apps/:appId/agents...). Distinct from the pi-agent launchers (opsy/cody/coder).
Selector and payload rules:
- app selector: exactly one of
--appIdor--appSlug - the parent agent is
--agentId; an individual sub-resource row is--id create/updateaccept--data/--from-file(JSON) plus camelCase convenience flags that map 1:1 onto the matchingCreate*Dto/Update*Dtosnake_casekeys- JSON flags are parsed from JSON; list flags (e.g.
--standardSuggestions,--supportedFileFormats,--ownerProductId) are comma-separated arrays createOnlyfields appear only oncreate;updateOnlyfields (e.g.--archived) only onupdate; incur rejects unknown flagsdeletereturns{ deleted: true, id }
Agent resource
| Command | Notes |
|---|---|
list / get / delete | --agentId for get/delete |
create | requires --skillName |
update | --agentId + changed fields; supports --archived |
upload | multipart image; --column (avatar/gallery_image), --file, --contentType |
create/update convenience flags: --name, --agentName, --skillName, --description, --category, --mode, --instructions, --welcomeMessage, --defaultAiModelId, --backupAiModelId, --cotAiModelId, --defaultReasoningLevel, --parent, --ownership (SYSTEM/APP/TENANT), --tenantAppId, --workDataSourceId, --status, --developmentStatus, --sortOrder, --temperature, --maxTokens, --isAgent, --isAssistant, --isSkill, --jsonOutput, --hasWorkflow, --multipleDeployment, --supportTools, --supportDataSources, --supportFiles, --supportKnowledgeBase, --supportWebSearch, --standardSuggestions (CSV), --supportedFileFormats (CSV), --ownerProductId (CSV), --instructionSchema (JSON), --inputFormSchema (JSON), --outputRenderSchema (JSON), --memoryOptions (JSON), --helpDocs (JSON), plus --data/--from-file. The long tail (compaction_*, context_clear_*, output_*, prompt_*, …) goes through --data/--from-file.
Sub-resource groups
Each group supports list/get/create/update/delete (unless noted). All take --appId/--appSlug and --agentId; row commands take --id. Key create flags shown.
| Group | Key create flags / notes |
|---|---|
models | DTO fields via flags or --data/--from-file |
tools | --coreAiToolId (required), --defaultParams (JSON), --tenantConnectionId, --tenantConnectionAccountId |
data-sources | --tenantDataSourceId (required), --privilege |
docs | DTO fields via flags or --data/--from-file |
mcps | DTO fields via flags or --data/--from-file |
connections | --connectedAiAgentId (required), --connectionType (required); routes via agent-connections segment |
dynamic-contexts | DTO fields via flags or --data/--from-file |
tasks | --parent_message_id (createOnly); --status/--error_message/--retry_count (updateOnly) |
recurring-tasks | backend requires cronExpression/nextRunAt |
workflow-steps | backend requires inputSchema/outputSchema |
deployments | nested arrays (tools) via --tools JSON or --data/--from-file |
deployment-tools | nested under a deployment; list/create/update/delete (no get); requires --deploymentId |
deployment-data-sources | same as deployment-tools |
workflow-jobs | read-only: list/get/traces/delete |
---
docyrus messaging
Tenant email account discovery and transactional email send. Routes through /v1/messaging/email/*. Requires the Messaging.Email.Send OAuth2 scope. Credentials are never returned.
docyrus messaging accounts
GET /messaging/email/accounts. Each account exposes id, name, provider, senderEmail, senderName, isUserAccessible, allowOverrideName, allowOverrideEmail, createdOn.
docyrus messaging email send
POST /messaging/email/accounts/:accountId/send
| Flag | Type | Description |
|---|---|---|
--accountId | string | Tenant email account UUID (required) |
--to / --cc / --bcc / --replyTo | string | Comma-separated addresses |
--subject | string | Subject (max 998 chars) |
--body | string | HTML or text body (max 1 000 000 chars) |
--sendAsUser | boolean | Send using the authenticated user's identity when allowed |
--data / --from-file | string | Full JSON payload; overrides individual flags |
Limits: up to 50 addresses per list, up to 10 attachments. Attachments are { filePath, fileName?, mimeType? } referencing tenant-scoped storage paths. Response: { messageId, provider, accepted, rejected }.
---
docyrus connect
Connector and action commands.
docyrus connect list-connectors
| Flag | Type | Default | Description |
|---|---|---|---|
--q | string | — | Keyword search on name, slug, or description |
--limit | number | 100 | Max results |
--offset | number | 0 | Result offset |
docyrus connect get-connector / get-action / list-connections
docyrus connect get-connector <slug>
docyrus connect get-action <slug> <actionKey>
docyrus connect list-connections <slug>get-connector returns data sources + actions; get-action returns input/output JSON schemas; list-connections returns tenant and user connections.
docyrus connect curl
Send an HTTP request through a connector's provider auth.
docyrus connect curl <slug> <endpoint> [options]| Flag | Alias | Type | Default | Description |
|---|---|---|---|---|
--method | -X | string | GET | HTTP method |
--data | -d | string | — | JSON payload (body for POST/PUT/PATCH, query for GET) |
--contentType | string | application/json | Content-Type header | |
--headers | string | — | JSON object of additional headers (can override Authorization) | |
--connectionId | -c | string | — | Tenant connection ID override |
--connectionAccountId | string | — | Connection account ID |
docyrus connect run-action
Run a connector action directly by provider slug + action key via POST /v1/connectors/:slug/actions/:actionKey/run. (To run a persisted app action, use apps actions run.)
docyrus connect run-action <slug> <actionKey> [options]| Flag | Alias | Type | Default | Description |
|---|---|---|---|---|
--params | -p | string | — | JSON object with action input parameters |
--connectionId | -c | string | — | Tenant connection ID override |
--connectionAccountId | string | — | Tenant connection account ID | |
--dryRun | -n | boolean | false | Preview the request without executing |
---
docyrus discover
Discovery commands for the tenant OpenAPI spec. All require an active login session. Commands other than discover api auto-download the spec if missing locally (public bucket -> authenticated GET /v1/api/openapi.json -> public retry).
| Command | Description |
|---|---|
discover api | Download tenant OpenAPI spec for the active tenant |
discover namespaces | List deduplicated namespace prefixes (e.g. /v1/users) |
discover path <prefix> | List endpoints (method + description) for a path prefix (/v1 optional) |
discover endpoint <selector> | Full endpoint object; selector /path (GET) or [METHOD]/path |
discover entity <name> | Full entity schema by name (case-sensitive, e.g. UserEntity) |
discover search <query> | Search endpoint paths and entity names (comma-separated terms) |
---
docyrus curl
Send arbitrary requests to the Docyrus API.
docyrus curl <path> [options]| Flag | Alias | Type | Description |
|---|---|---|---|
--request | -X | string | HTTP method |
--header | -H | array | Request header (repeatable) |
--data | -d | string | Request payload |
--get | -G | boolean | Send data as query string |
--include | -i | boolean | Include status and response headers |
--noAuth | boolean | Skip Authorization header |
Notes: path-only (no absolute URLs); /v1 prefix auto-normalized; JSON payloads auto-detect Content-Type: application/json; default method GET (POST if -d provided).
---
docyrus docy
Chat with the platform's main AI agent.
docyrus docy "<prompt>"| Flag | Type | Description |
|---|---|---|
--agentId | string | Agent ID; defaults to the Docyrus CLI agent |
--deploymentId | string | Optional agent deployment ID |
Renders markdown in a TTY; preserves structured output with --json/--verbose/--format.
---
docyrus opsy / cody / coder (pi agents)
Launch the pi agent runtime. opsy = Cowork Agent; cody = Coding Agent (coder is an alias of cody). Each takes an optional prompt argument (omit to open the interactive TUI).
| Flag | Type | Description |
|---|---|---|
--print | boolean | One-shot print mode instead of the TUI |
--mode | string | Print mode output: text or json |
--continue | boolean | Continue the previous pi session |
--resume | boolean | Open the pi session picker |
--provider | string | Model provider |
--model | string | Model pattern or full provider/model id |
--thinking | string | Thinking level |
--session / --sessionDir | string | Specific session file / storage dir override |
--apiKey | string | Temporary provider API key override for this run |
--verbose | boolean | Verbose pi startup output |
---
docyrus server
Start an HTTP server bridging a pi agent to the AI SDK useChat protocol (SSE chat stream with reconnect/resume).
| Flag | Type | Default | Description |
|---|---|---|---|
--profile | string | coder | Agent profile to use |
--port | number | 3111 | Server port |
--provider / --model / --thinking | string | — | Model selection |
--sessionDir | string | — | Session storage directory override |
--apiKey | string | — | Temporary provider API key override |
--auth | string | — | Require this bearer token for all HTTP requests |
--verbose | boolean | — | Verbose pi startup output |
--sandbox | boolean | — | Enable sandbox browser mode (remote Cloudflare Browser Rendering) |
--desktop | boolean | — | Enable desktop browser automation tools (docyrus_browser_*) |
---
docyrus browser
Browser automation (local Chrome on :9222 or remote Cloudflare). Commands return JSON with a mode field.
| Command | Description | Key flags / args |
|---|---|---|
start | Start a session | --profile (copy default Chrome profile, local only) |
close | Close the session | --kill (kill local Chrome) |
nav <url> | Navigate / open URL | --new, --reload |
tabs | List/switch tabs | --switch <index> |
info | Page URL, title, viewport, scroll | — |
snapshot | Compact element refs (@e1) for interaction | --all, --selector |
click <target> [y] | Click ref @e1, CSS selector, or x y coords | --timeout |
fill <target> <value> | Type into input/textarea | --timeout |
select <target> <value> | Select a dropdown option | --timeout |
eval <code> | Evaluate JS in the active tab | --timeout |
wait [ms] | Wait for delay/condition | --idle, --selector, --url, --timeout |
screenshot | Capture the tab | --full, --base64 |
content <url> | Extract readable markdown | — |
cookies | Show cookies | --name, --domain |
console | Capture console messages | --level, --listen <ms> |
network | Inspect captured requests | --method, --status, --url, --listen <ms> |
devtools <subcommand> | Read @docyrus/devtools state/errors/issues/console | --level |
run-script <script> | Run a CDP script file | --appSlug, --appId, --keepAlive |
---
docyrus knowledge
Repo knowledge-graph commands operating on docyrus/knowledge. Local dev-workflow tooling.
| Command | Description |
|---|---|
init | Initialize docyrus/knowledge + external-agent integration files (--brief, --installGitHook) |
generate-initial | Generate/refresh starter structure from repo facts (brief arg) |
refresh | Refresh managed starter files (--staged, --sections) |
search <query> | Semantic search (--limit, --reindex) |
section <query> | Show a section with refs and backlinks |
locate <query> | Find sections by exact/short/fuzzy match |
refs <query> | Find markdown/code references to a section or symbol (--scope) |
expand [text] | Expand [[refs]] into resolved context (--stdin) |
check | Validate the graph (links/backlinks) |
doctor | Explain drift, quality issues, hot spots |
config | Show resolved graph/cache/provider config |
list-impacted | List sections likely impacted by changes (--staged) |
audit-staged | Run a staged-diff knowledge audit |
pre-commit | Hook-oriented staged knowledge gate |
hook <agent> <event> | Internal hook command for external-agent integrations |
---
docyrus project-plan
Repo-tracked project plan graph (phases -> features -> tasks). Token-efficient list/find/upsert/status commands. Local dev-workflow tooling.
| Command | Description |
|---|---|
ensure / check / config | Ensure graph exists / validate / show resolved paths |
show / summary | Show hierarchy / summary statistics |
list-phases / list-features / list-tasks | Slim listings (list-tasks: --phaseId, --featureId, --status, --limit, --includeSummary) |
find-tasks | Filter tasks (--title, --titleContains, --summaryContains, --status, --type, --assignee, --featureId, --phaseId, --taskId, --limit) |
get-task | Get a task with linked local subtasks (--taskId) |
upsert-phase / upsert-feature / upsert-task | Create/update graph nodes |
set-order | Set display order of a phase/feature/task (--order) |
set-task-status | Update a task status (--taskId, --status) |
create-linked-todo | Create a local .pi/todos subtask linked to a task |
upsert-from-architect / upsert-from-plan | Internal sync from /architect and /plan artifacts |
---
docyrus release
Release and versioning commands.
docyrus release status
Show current release status and unreleased changes.
docyrus release new-version
Create a new release with version bump, changelog generation, and optional GitHub release.
| Flag | Type | Description |
|---|---|---|
--bump | string | SemVer bump type (auto-detect if omitted) |
--version | string | Explicit target version (e.g. 1.0.0) |
--appId | string | App ID for the release record; defaults to DOCYRUS_SANDBOX_APP_ID |
--dryRun | boolean | Preview changes without committing |
--skipChangelog / --skipTag / --skipGithubRelease / --skipDbRelease | boolean | Skip individual steps |
---
docyrus tui
Launch the OpenTUI terminal UI.
Notes:
- requires Bun installed locally
- reuses the existing CLI command graph
- intended for interactive terminal usage rather than browser embedding
DSQL Reference — Capabilities, Limitations & Pseudo-Functions
DSQL (Docyrus Structured Query Language) is a read-only, PostgreSQL-compatible SQL dialect that runs over logical data-source tables instead of physical tables. You write SELECT queries against logical names like base.contact, and the engine resolves them to the correct tenant schema, applies row-level access control, and enforces a strict allow-list of statements and functions.
This reference documents exactly what DSQL supports and rejects. It is derived from the engine implementation (LogicalSqlQueryRunner, DsqlSchema, DsqlAccessPlanner), not from generic Postgres behavior — where the two differ, this file is authoritative.
Run DSQL from the CLI:
```bash
docyrus dsql query "select id, email from base.contact limit 100"
docyrus dsql query --from-file ./report.sql
docyrus dsql schema app base # discover queryable tables + columns
docyrus dsql schema data-source base contact
docyrus dsql schema data-sources --ids ds-1,ds-2
```
Always discover the schema first — never guess table or field slugs.
>
Not sure how to write the SQL?docyrus dsql generate "<question>"turns a natural-language question into a DSQL query via the DSQL generator agent, anddocyrus dsql ask "<question>"generates it and runs it in one step. The agent follows every rule in this document.
---
1. Logical table naming
Tables are addressed as `appSlug.dataSourceSlug` (schema-qualified logical names). Unqualified table names are rejected unless they are a CTE alias.
select * from base.task t
select * from crm.contact c
select * from custom.my_source s| Logical namespace | What it holds |
|---|---|
<appSlug>.<dataSourceSlug> | Business data sources for an app (e.g. base.task, crm.lead). Subject to access control. |
tenant.user | The logical users table. Join target for owner/assignee names and emails. Its primary key is exposed as id (the physical user_id is hidden). |
tenant.enum | The logical enum/option table. Join target to resolve enum labels, colors, icons, and metadata. |
Physical resolution (informational — you never write these): global datasets map to the dataset schema, SYSTEM data sources to public, everything else to the tenant's private schema.
External data sources cannot be queried — any source backed by an external SQL provider is rejected with External data source '…' is not supported by the SQL query endpoint.
Child / inherited sources
Some data sources inherit fields from a parent ("base") source. You query the child logical source directly; when you reference an inherited (base) field, the engine auto-injects a LEFT JOIN to the base table on base.id = child.id. You do not write that join yourself.
- A child whose base is a simple-type source is not queryable (
Simple base data source '…' is not supported).
---
2. Field referencing
Reference fields by logical field slug, in one of three forms (resolved in this order):
| Form | Example | Notes |
|---|---|---|
| Unqualified | email | Resolved across all in-scope sources; errors if ambiguous across joined tables. |
| Alias-qualified | c.email | Preferred whenever more than one source is in scope. |
| Fully-qualified | crm.contact.email | Explicit app + source + field. |
- `id` is always available on every logical source (a synthetic UUID is provided if the source has no natural id). For
tenant.user,idis the user's id. - Simple-source custom fields are stored internally in a JSONB
datacolumn but are exposed as regular columns by slug — querys.amount, nots.data->'amount'. - Virtual / computed field types are NOT queryable and are omitted from the schema:
field-list,field-display,field-formula,field-taskList,field-button. Referencing one throwsField '…' is not supported by the SQL query endpoint. - Internal columns are hidden and not selectable:
tenant_id,tenant_data_source_id,cursor_date,sort_order,style,docyment,parent_data_source_id,parent_record_id,editor_view_id,followers,mentions(and the rawdatacolumn on simple sources).
---
3. Supported SQL surface
DSQL accepts exactly one read-only `SELECT` statement. Within that statement you may use:
SELECT(includingDISTINCT),FROM,WHERE,GROUP BY,HAVING,ORDER BY,LIMIT,OFFSET- Joins:
INNER,LEFT,RIGHT,FULL,CROSS, plus implicit joins viaWHERE - CTEs (
WITH …) — read-only only - Subqueries in
SELECT,WHERE, andFROM(aFROMsubquery must be aliased) - Set operations:
UNION/UNION ALL/INTERSECT/EXCEPT(each side is itself a validatedSELECT) - Aggregates and
GROUP BY/HAVING ORDER BYmay reference aSELECT-list alias- Type casts with
::type(see §6)
SELECT * is allowed but must be unambiguous: with more than one source in FROM, qualify it (t.*), and * may only appear in the SELECT list.
---
4. Hard restrictions
Rejected at parse/compile time (before any execution):
- Only `SELECT`. Every non-select statement type is blocked:
INSERT,UPDATE,DELETE,MERGE,CALL,DO, allCREATE*/ALTER*/DROP*,TRUNCATE,COPY,GRANT,INDEX,VACUUM,SET/SHOW,NOTIFY/LISTEN,BEGIN/COMMIT(transactions), andEXPLAIN. - Exactly one statement — no multiple semicolon-separated statements.
- No `SELECT INTO`.
- No data-modifying CTEs (a
WITHbranch that is anything other than aSELECT). - No functions/`LATERAL` in `FROM` (
Functions in FROM are not supported). Set-returning functions as a table source are not allowed. - No unqualified physical/table names — only
appSlug.dataSourceSluglogical names (or CTE aliases). - *No `pg_
functions** and no access to physical tenant schemas orpublic` tables directly. - Read-only execution: the query runs inside a
readOnlytransaction with a 15-second statement timeout.
---
5. Supported functions (allow-list)
Only the functions below may be called. Names are matched case-insensitively. Anything else throws Function '…' is not supported.
String length, lower, upper, substr, replace, concat, trim, ltrim, rtrim, btrim, split_part, initcap, reverse, strpos, lpad, rpad
Number abs, ceil, floor, round, sqrt, power, mod, gcd, lcm, exp, ln, log, log10, log1p, pi, sign, width_bucket, trunc, greatest, least
Date / time now, age, clock_timestamp, date_part, date_trunc, extract, isfinite, justify_days, justify_hours, make_date, make_time, make_timestamp, make_timestamptz, timeofday, to_timestamp, to_char, to_date, to_time
JSON / JSONB jsonb_array_length, jsonb_extract_path, jsonb_extract_path_text, jsonb_object_keys, jsonb_build_object, json_build_object, array_to_json, row_to_json
Utility coalesce
Aggregates (callable as aggregates only) count, sum, avg, min, max, array_agg, json_agg, jsonb_agg
Allowed bare literals: current_date, current_time, current_timestamp.
Not supported (common surprises)
- Window functions: dedicated window functions (
row_number,rank,dense_rank,lead,lag,ntile,first_value, …) are not on the allow-list and are rejected. Do not rely onOVER (…)windowing — it is outside the supported surface. - Explicitly blocked:
current_setting,set_config,version,pg_sleep,pg_read_file,pg_read_binary_file,inet_server_addr,inet_server_port, and everything prefixed `pg_`. - Anything not in the lists above (e.g.
string_agg,regexp_replace,position,left/right,nullif,case-as-function,generate_series) — if you need it, restructure the query or post-process the result. - Schema-qualified function calls are only allowed as
pg_catalog.<name>(and still must resolve to an allow-listed name).
---
6. Type casts
::type casts are restricted to this set (scalar and [] array variants):
int, int2, int4, int8, bigint, real, float, float4, float8, numeric, decimal, double, money, timestamp, timestamptz, date, time, interval, bool, boolean, uuid, text
---
7. tenant.* pseudo-functions
These are DSQL-only helpers (not real Postgres functions) that inject the current user's identity and organizational scope into your query. They are translated to SQL at compile time. Use them in WHERE/SELECT to write permission- and org-aware queries. Each takes 0 or 1–2 UUID arguments as shown; an argument-count mismatch throws tenant.X expects N argument(s).
Identity & context (no args)
| Function | Returns |
|---|---|
tenant.current_user_id() | Current user's UUID |
tenant.active_user_id() | Alias of current_user_id() |
tenant.current_tenant_id() | Current tenant's UUID |
tenant.current_role_id() | Current user's primary role UUID (or NULL) |
tenant.current_role_ids() | UUID[] of all the current user's role ids |
tenant.current_team_ids() | UUID[] of the current user's team ids |
tenant.current_hierarchy_unit_id() | Current user's org-unit UUID (or NULL) |
tenant.current_scope_user_ids() | UUID[] of users within the current user's visibility scope |
User matching (1 arg → boolean)
| Function | True when |
|---|---|
tenant.is_current_user(userId) / tenant.active_user(userId) | userId is the current user |
tenant.is_not_current_user(userId) / tenant.not_active_user(userId) | userId is not the current user (or is NULL) |
Scope membership (1 arg → boolean)
| Function | True when |
|---|---|
tenant.in_current_user_scope(userId) / tenant.user_in_current_scope(userId) / tenant.user_in_current_hierarchy_scope(userId) | userId is inside the current user's scope |
tenant.not_in_current_user_scope(userId) / tenant.user_not_in_current_scope(userId) / tenant.user_not_in_current_hierarchy_scope(userId) | negation of the above |
Role membership
| Function | Args | True when |
|---|---|---|
tenant.in_role(userId, roleId) / tenant.user_in_role(userId, roleId) | 2 | userId has role roleId |
tenant.not_in_role(userId, roleId) / tenant.user_not_in_role(userId, roleId) | 2 | negation |
tenant.in_current_roles(userId) / tenant.user_in_current_roles(userId) | 1 | userId shares a role with the current user |
tenant.not_in_current_roles(userId) / tenant.user_not_in_current_roles(userId) | 1 | negation |
tenant.current_user_in_role(roleId) | 1 | the current user has role roleId |
Team membership
| Function | Args | True when |
|---|---|---|
tenant.in_team(userId, teamId) / tenant.user_in_team(userId, teamId) | 2 | userId is in team teamId |
tenant.not_in_team(userId, teamId) / tenant.user_not_in_team(userId, teamId) | 2 | negation |
tenant.in_current_user_team(userId) / tenant.in_active_user_team(userId) / tenant.user_in_current_teams(userId) | 1 | userId shares a team with the current user |
tenant.not_in_current_user_team(userId) / tenant.not_in_active_user_team(userId) / tenant.user_not_in_current_teams(userId) | 1 | negation |
tenant.current_user_in_team(teamId) | 1 | the current user is in team teamId |
Hierarchy-unit membership
| Function | Args | True when |
|---|---|---|
tenant.in_unit(userId, unitId) / tenant.user_in_unit(userId, unitId) | 2 | userId is in unit unitId (exact unit) |
tenant.not_in_unit(userId, unitId) / tenant.user_not_in_unit(userId, unitId) | 2 | negation |
tenant.in_sub_unit(userId, unitId) / tenant.user_in_sub_unit(userId, unitId) / tenant.user_in_sub_units(userId, unitId) | 2 | userId is in unitId or any descendant unit |
tenant.not_in_sub_unit(userId, unitId) / tenant.user_not_in_sub_unit(userId, unitId) / tenant.user_not_in_sub_units(userId, unitId) | 2 | negation |
tenant.current_user_in_unit(unitId) | 1 | the current user is in unit unitId |
---
8. Limits & execution
| Limit | Value |
|---|---|
| Max query length | 100,000 characters |
Default LIMIT (when none given) | 100 rows |
Max LIMIT — interactive/user context | 1,000 rows |
Max LIMIT — API client (app token) context | 100 rows |
| Statement timeout | 15 seconds, read-only transaction |
- If you omit
LIMIT, the engine wraps the query and applies the default. If you request more than the cap, it is silently clamped to the cap.LIMIT ALLor a non-literal limit falls back to the default. NegativeLIMITis rejected. - For totals/aggregates, do the aggregation in SQL (
count,sum, …) rather than fetching rows and counting client-side.
---
9. Access control & scopes
DSQL enforces the same row-level security as the rest of the platform — you only ever see rows you are permitted to see.
- Business sources (any app slug other than
core/tenant) require a view ACL for the current user's roles; otherwise the query fails with 403 `Access denied to logical data source '…'`. Role-restriction queries (hidden-level restrictions) and child-relation filters are injected automatically. - `PRIVATE` data-access sources require a
record_ownerfield and limit visibility to the owner and their hierarchy subordinates (gated by the source's unit-peer-access level). - `core`/`tenant` sources skip source ACL but still apply tenant scoping.
OAuth scopes (when called with an app/API token):
DS.Read.AllorDS.ReadWrite.All→ all data sources.- Per-source:
DS.Read.{Slug}orDS.ReadWrite.{Slug}, where{Slug}is the PascalCase ofappSlug_dataSourceSlug(e.g.base.contact→DS.Read.BaseContact). - Delegated user-context tokens (
openid/profile/email/offline_access) are not subject to the per-source scope gate. - A missing scope throws an insufficient-scope error listing the scope(s) required.
The CLI docyrus dsql commands send the active session's token, so interactive limits (max 1,000 rows) and delegated-scope rules apply.
---
10. Error catalog & recovery
All DSQL errors are QueryBuilderErrors (HTTP 400 unless noted). Common ones and how to fix:
| Message | Cause | Fix |
|---|---|---|
Only SELECT statements are supported | DML/DDL or non-select statement | Use a single SELECT. |
Exactly one SELECT statement is supported | Multiple statements | Send one statement; combine with UNION if needed. |
Query exceeds the maximum length of 100000 characters | Query too long | Shorten / parameterize. |
Unqualified table 'X' is not a logical data source or CTE alias | Bare table name | Use appSlug.dataSourceSlug or define a CTE. |
Unknown logical data source 'app.source' | Wrong slug / not queryable | Re-run dsql schema app <appSlug> and copy exact slugs. |
External data source '…' is not supported | Source backed by external provider | Not queryable via DSQL. |
Unknown field 'slug' / Unknown field 'slug' on 'app.source' | Wrong field slug | Check schema; qualify with alias. |
Field '…' is not supported by the SQL query endpoint | Virtual field (field-formula/field-list/…) | Not queryable; derive it in SQL or omit. |
Function 'X' is not supported | Function not on allow-list (or pg_*) | Replace with an allow-listed function or post-process. |
tenant.X expects N argument(s) | Wrong pseudo-function arity | Match the signature in §7. |
Subqueries in FROM must have an alias | Unaliased FROM (SELECT …) | Add an alias. |
Bare * is ambiguous with multiple FROM sources | SELECT * across joins | Qualify: t.*. |
Duplicate table alias 'X' | Reused alias | Give each source a distinct alias. |
Access denied to logical data source '…' (403) | No view ACL | You lack permission for that source. |
When a query fails: read the message, fix against the schema and the rules above, and retry. If it suggests a wrong source/field, go back to dsql schema … discovery.
---
11. Patterns
-- Resolve owner name/email via tenant.user
select t.id, t.title, u.full_name as owner
from base.task t
left join tenant.user u on u.id = t.record_owner
order by t.created_on desc
limit 50;
-- Resolve a status enum label/color via tenant.enum
select c.id, c.name, e.name as status_label, e.color
from crm.contact c
left join tenant.enum e on e.id = c.status;
-- Status breakdown, aggregated in SQL
select e.name as status, count(*) as total
from base.task t
left join tenant.enum e on e.id = t.status
group by e.name
order by total desc;
-- "My records" using identity pseudo-functions
select t.id, t.title
from base.task t
where tenant.is_current_user(t.record_owner)
limit 100;
-- Records owned by anyone in the current user's hierarchy scope
select t.id, t.title, t.record_owner
from base.task t
where tenant.in_current_user_scope(t.record_owner);---
12. Differences from standard PostgreSQL (gotchas)
- You query logical names (
appSlug.dataSourceSlug), never physical tables. Bare/unqualified table names are rejected. - The function surface is a strict allow-list — many everyday Postgres functions (window functions,
string_agg,regexp_*,nullif,left/right,position,generate_series) are unavailable. idis guaranteed on every source; the physicaluser_idontenant.useris hidden behindid.- Virtual/computed Docyrus fields don't exist as columns.
- Every query is implicitly row-level-secured and clamped by a
LIMITcap; "see everything" is not possible. tenant.*are pseudo-functions, not real functions — they only work inside DSQL.
List Query Examples
Practical examples for docyrus ds list with columns, filters, sorting, pagination, and the advanced query engine (keyword search, calculations, formulas, pivots, child queries).
JSON flags (--filters, --calculations, --formulas, --pivot, --childQueries, etc.) take the same payload shapes the /items query endpoint accepts. For the full payload reference see the docyrus-platform skill's data-source-query-guide.md.
---
Table of Contents
1. Basic Listing 2. Column Selection 3. Filtering 4. Sorting 5. Pagination 6. Combined Examples 7. Advanced Queries
---
Basic Listing
List all records with default columns:
docyrus ds list crm contactsList with JSON output:
docyrus ds list crm contacts --format json---
Column Selection
Select specific fields:
docyrus ds list crm contacts --columns "name, email, phone"Select with relation expansion (get related account's name):
docyrus ds list crm contacts --columns "name, email, related_account(account_name)"Spread related fields into root object:
docyrus ds list crm contacts --columns "name, ...related_account(account_name, account_phone)"Alias columns:
docyrus ds list crm contacts --columns "n:name, e:email, p:phone"---
Filtering
Single field equals
docyrus ds list crm contacts --filters '{"rules":[{"field":"status","operator":"=","value":"active"}]}'Multiple conditions (AND)
docyrus ds list crm contacts --filters '{"combinator":"and","rules":[{"field":"status","operator":"=","value":"active"},{"field":"priority","operator":">=","value":3}]}'OR conditions
docyrus ds list crm contacts --filters '{"combinator":"or","rules":[{"field":"city","operator":"=","value":"Istanbul"},{"field":"city","operator":"=","value":"Ankara"}]}'IN operator (match any value in list)
docyrus ds list crm contacts --filters '{"rules":[{"field":"status","operator":"in","value":[1,2,3]}]}'Not equal
docyrus ds list crm contacts --filters '{"rules":[{"field":"status","operator":"!=","value":"archived"}]}'Text search with LIKE
docyrus ds list crm contacts --filters '{"rules":[{"field":"name","operator":"like","value":"John"}]}'Empty / not empty
docyrus ds list crm contacts --filters '{"rules":[{"field":"email","operator":"not empty"}]}'docyrus ds list crm contacts --filters '{"rules":[{"field":"phone","operator":"empty"}]}'Date shortcuts
Records created this month:
docyrus ds list crm contacts --filters '{"rules":[{"field":"created_on","operator":"this_month"}]}'Records created today:
docyrus ds list crm contacts --filters '{"rules":[{"field":"created_on","operator":"today"}]}'Records from last 30 days:
docyrus ds list crm contacts --filters '{"rules":[{"field":"created_on","operator":"last_30_days"}]}'Date range with between
docyrus ds list crm contacts --filters '{"rules":[{"field":"created_on","operator":"between","value":["2025-01-01","2025-06-30"]}]}'Filter on related field
Filter by related account's status:
docyrus ds list crm contacts --filters '{"rules":[{"field":"rel_related_account/account_status","operator":"=","value":1}]}'Current user filter
Records owned by current user:
docyrus ds list crm contacts --filters '{"rules":[{"field":"record_owner","operator":"active_user"}]}'Nested AND + OR
Active contacts created this month OR contacts with high priority:
docyrus ds list crm contacts --filters '{"combinator":"or","rules":[{"combinator":"and","rules":[{"field":"status","operator":"=","value":"active"},{"field":"created_on","operator":"this_month"}]},{"field":"priority","operator":">=","value":5}]}'---
Sorting
Sort by name ascending (default):
docyrus ds list crm contacts --orderBy "name"Sort by created date descending:
docyrus ds list crm contacts --orderBy "created_on DESC"---
Pagination
First 10 records:
docyrus ds list crm contacts --limit 10Next 10 records (page 2):
docyrus ds list crm contacts --limit 10 --offset 10Get total count alongside results:
docyrus ds list crm contacts --limit 10 --fullCount true---
Combined Examples
Active contacts with email, sorted by name, paginated
docyrus ds list crm contacts \
--columns "name, email, phone, created_on" \
--filters '{"rules":[{"field":"status","operator":"=","value":"active"},{"field":"email","operator":"not empty"}]}' \
--orderBy "name" \
--limit 25 \
--fullCount trueRecent high-priority deals with account info
docyrus ds list crm deals \
--columns "name, amount, stage, ...related_account(account_name)" \
--filters '{"combinator":"and","rules":[{"field":"priority","operator":">=","value":4},{"field":"created_on","operator":"last_30_days"}]}' \
--orderBy "amount DESC" \
--limit 20Search for records by keyword
docyrus ds list crm contacts \
--columns "name, email, phone" \
--filters '{"rules":[{"field":"name","operator":"like","value":"Smith"}]}' \
--format jsonExport all records as JSON lines
docyrus ds list crm contacts \
--columns "id, name, email, phone, status, created_on" \
--format jsonlRecords owned by current user, created this quarter
docyrus ds list crm tasks \
--columns "name, status, priority, due_date" \
--filters '{"combinator":"and","rules":[{"field":"record_owner","operator":"active_user"},{"field":"created_on","operator":"this_quarter"}]}' \
--orderBy "due_date" \
--limit 50---
Advanced Queries
Keyword search
Full-text keyword filter across searchable fields:
docyrus ds list crm contacts --columns "name, email" --filterKeyword "renewal"Calculations (aggregations / group-by)
Group by a column (via --columns) and aggregate with --calculations. Each rule is { field, func, name, isDistinct? } (func: count, sum, avg, min, max). Add --groupSummaries to include per-group summary rows.
# Count open tasks per owner
docyrus ds list crm tasks \
--columns "record_owner(name)" \
--calculations '[{"field":"id","func":"count","name":"open_tasks"}]' \
--filters '{"rules":[{"field":"task_status","operator":"=","value":1}]}' --json
# Multiple aggregations per category, with group summaries
docyrus ds list crm deals \
--columns "category" \
--calculations '[{"field":"id","func":"count","name":"total"},{"field":"amount","func":"sum","name":"totalAmount"},{"field":"amount","func":"avg","name":"avgAmount"}]' \
--groupSummaries --json
# Distinct count
docyrus ds list crm contacts \
--calculations '[{"field":"email","func":"count","name":"unique_emails","isDistinct":true}]' --jsonFormulas (computed columns)
--formulas is a { name: definition } object; each name must also appear in --columns.
# Inline math formula
docyrus ds list crm accounts \
--columns "id, name, balance_pct" \
--formulas '{"balance_pct":{"inputs":[{"kind":"math","op":"/","inputs":[{"kind":"column","name":"balance"},{"kind":"literal","literal":100}]}]}}' --json
# Subquery formula (count child records)
docyrus ds list crm accounts \
--columns "id, name, contacts_count" \
--formulas '{"contacts_count":{"from":"crm_contacts","with":"account","inputs":[{"kind":"aggregate","name":"count","inputs":[]}]}}' --jsonPivot
--pivot builds a matrix of cross-joined dimensions left-joined onto the main query, so every combination appears even with zero matches.
docyrus ds list crm orders \
--columns "...order_status(orderStatus:name)" \
--pivot '{"matrix":[{"using":"created_on","columns":"day:to_char[DD/MM/YYYY]@created_on","dateRange":{"interval":"day","min":"2025-09-01T00:00:00Z","max":"2025-09-30T00:00:00Z"},"spread":true}]}' --jsonChild queries (nested records)
--childQueries embeds related rows under an alias that must also appear in --columns. Each entry is { alias, from, using, columns?, filters?, calculations?, orderBy?, limit? }; from uses appSlug_slug and using is the child field referencing the parent id.
docyrus ds list crm accounts \
--columns "id, name, recent_deals" \
--childQueries '[{"alias":"recent_deals","from":"crm_deals","using":"account","columns":"name, amount","orderBy":"created_on DESC","limit":5}]' --jsonExpand and distinct columns
# Expand related/nested columns
docyrus ds list crm contacts --columns "name, email" --expand "related_account" --json
# Deduplicate rows by selected columns (e.g. one row per email)
docyrus ds list crm contacts --columns "email, name, created_on" --distinctColumns "email" --jsonRelated skills
FAQ
Which Docyrus CLI areas does docyrus-cli-app cover?
docyrus-cli-app spans authentication, environment and tenant switching, docyrus ds data records, docyrus studio schema objects, docyrus automation graphs, messaging email sends, OpenAPI discovery, and the docyrus tui terminal UI.
What Studio objects can docyrus-cli-app manage?
docyrus-cli-app manages Studio data sources, fields, enums, data views, forms, webforms, HTML templates, PDF templates, DOCX export templates, and email templates through docyrus studio subcommands.
Is Docyrus Cli App safe to install?
skills.sh reports 2 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.