Skip to content
Back to skills

Yandex 360 Datalens

ASecurity

Use when reading or changing Yandex DataLens through ycli — collections, workbooks and the entries they hold (connections, datasets, charts, reports, dashboards and the rest), the roles on them, the export and import of a workbook, embedding, the audit, the members of the organization, and how to sign in to DataLens — via the `ycli datalens` CLI, the `datalens_*` MCP tools, or the DataLensClient SDK.

  • 4 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 6, 2026
ai-agentspythongoshellsqlnodeapidatabase

Works with

  • cli
  • api
  • mcp

Security analysis

A100/100

Scanned October 7, 2026

npx -y skills add bim-ba/ycli --skill yandex-360-datalens --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Yandex 360 Datalens?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Yandex 360 Datalens
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/bim-ba-yandex-360-datalens/badge)](https://www.skillsdirectory.com/skills/bim-ba-yandex-360-datalens)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: yandex-360-datalens
description: >-
  Use when reading or changing Yandex DataLens through ycli — collections,
  workbooks and the entries they hold (connections, datasets, charts, reports,
  dashboards and the rest), the roles on them, the export and import of a
  workbook, embedding, the audit, the members of the organization, and how to
  sign in to DataLens — via the `ycli datalens` CLI, the `datalens_*` MCP tools,
  or the DataLensClient SDK.
---
# Yandex 360 DataLens

Drive Yandex DataLens via `ycli` through the CLI, the `datalens_*` MCP tools, or the `DataLensClient` SDK.

**In progress.** ycli wraps DataLens section by section, and this skill grows with each one. Wrapped today, reads and writes unless said otherwise (one line a section):

- collections (the folders that hold workbooks) and workbooks
- the export of a workbook as one document and its import as a new workbook
- entries as such: finding them, their relations, revisions and permissions, renaming, locks
- connections
- datasets, with their rows
- charts built in the wizard, in QL and in the editor, and the data of a saved chart
- reports
- dashboards
- HTML pages, with a temporary link that shows one
- the embeds of an entry and the keys for embedding that sign them
- the roles on a shared entry
- the audit (reads)
- saved SQL queries (experimental in the API; written from its document, not measured)
- cloud environments and their storage bucket (experimental in the API; the listing measured, the rest written from the document and never called)
- REST catalogs and Lakehouse operations (experimental in the API; the listing of catalogs measured, the rest written from the document and never called)
- Trino clusters and their resource presets (experimental in the API; the listing of clusters measured, the rest written from the document and never called)
- Spark clusters and their resource presets (experimental in the API; written from the document, not measured, the writes never called)
- Spark applications: listing, reading, making, cancelling one and reading its log (experimental in the API; written from the document, not measured)
- the members of the organization and the details of the DataLens instance (reads)
- the licences (seats) of the instance: reads measured; giving a licence and setting the limit written from the document, never called

## When to use

- Finding a collection or a workbook: listing the root and descending
- Listing what a workbook holds: its connections, datasets, charts and dashboards
- Creating, renaming, moving or deleting collections and workbooks
- Exporting everything a workbook holds as one document, and making a new workbook from it
- Listing, creating, changing or deleting the embeds of a chart or a dashboard, and the keys for embedding of a workbook
- Seeing or changing who has which role on a collection, a workbook or a shared entry
- Asking the audit which entries changed in a period, and what one user may do with an entry
- Finding an entry anywhere by kind or name, what it uses and what uses it, its revisions
- Checking what you may do with entries, workbooks and collections
- Renaming an entry, or locking it while you edit
- Finding the user, group or service account to give a role to
- Reading, creating, changing or deleting a connection to a database, a file or an API
- Reading, creating, changing, checking or deleting a dataset, and reading its rows
- Reading the data a saved chart shows
- Reading, creating, saving or deleting a chart of the wizard, a QL chart or a chart of the editor
- Reading, creating, saving or deleting a dashboard
- Checking that the credentials reach DataLens, and which instance they reach
- Setting up the credentials DataLens needs, which differ from Tracker, Wiki and Forms

## When NOT to use

- Reading or editing Tracker issues — use `yandex-360-tracker`
- Reading or editing Wiki pages — use `yandex-360-wiki`
- Reading or editing Forms — use `yandex-360-forms`

## Surfaces

- **CLI** — `uv run ycli datalens <group> <cmd>`
- **MCP** — `datalens_*` tools, reads and writes. Write tools carry honest annotations (`readOnlyHint=False`, explicit `destructiveHint`); `ycli mcp start --read-only` hides them.
- **SDK** — `from ycli.yandex.datalens.client import DataLensClient` → `DataLensClient(auth=IAMTokenAuth(SecretStr(…)), cloud_organization_id=…)` (`IAMTokenAuth` from `ycli.yandex.core.auth`)

---

## 1. Auth and hosts

Public API (`api.datalens.tech`), every operation is `POST /rpc/<name>`:

```text
Authorization: Bearer $YANDEX_CLOUD_IAM_TOKEN
x-dl-org-id: $YANDEX_CLOUD_ORGANIZATION_ID
x-dl-api-version: 3
```

DataLens differs from the other services in both credentials:

- **The token is an IAM token, not an OAuth token.** Set `YANDEX_CLOUD_IAM_TOKEN` (`yc iam create-token`; it lives up to 12 hours) or a service account's key in `YANDEX_CLOUD_SERVICE_ACCOUNT_KEY_FILE`. A Yandex ID OAuth token (`YANDEX_ID_OAUTH_TOKEN`) is not taken. ycli holds one way to sign in at a time.
- **The organization is a Yandex Cloud organization**, in `YANDEX_CLOUD_ORGANIZATION_ID`; the Yandex 360 organization id does not name it.

**Not configured is not a failure.** With an OAuth token, or without a Yandex Cloud organization, `ycli auth status` lists `datalens` as not configured (`"configured": false`, `detail` says what to set) and still exits 0; `ycli doctor` skips it. A `ycli datalens …` command then exits 2 with the same text and sends nothing.

**403 `LICENSE_IS_REQUIRED`** means the account has no DataLens seat in that organization: the instance details still answer, every other operation is refused.

---

## 2. Reading

| Operation | CLI | MCP tool |
|-----------|-----|----------|
| Auth probe (the DataLens instance) | `uv run ycli datalens tenant details-get` | `datalens_tenant_details_get` |
| Probe only this service | `uv run ycli datalens auth status` | — |
| What the root holds | `uv run ycli datalens collections content-list` | `datalens_collections_content_list` |
| What a collection holds | `uv run ycli datalens collections content-list <collection_id> [--mode onlyWorkbooks] [--all]` | `datalens_collections_content_list` |
| One collection | `uv run ycli datalens collections get <collection_id>` | `datalens_collections_get` |
| Several collections by id | `uv run ycli datalens collections list-by-ids <id> <id>…` | `datalens_collections_list_by_ids` |
| Path from the root | `uv run ycli datalens collections breadcrumbs-list <collection_id>` | `datalens_collections_breadcrumbs_list` |
| What you may create in the root | `uv run ycli datalens collections permissions-get-root` | `datalens_collections_permissions_get_root` |
| Who has which role | `uv run ycli datalens collections access-bindings-list <collection_id> [--get-inherited-bindings]` | `datalens_collections_access_bindings_list` |
| Workbooks of the root, or of one collection | `uv run ycli datalens workbooks list [--collection-id <id>] [--filter-string …] [--all]` | `datalens_workbooks_list` |
| One workbook | `uv run ycli datalens workbooks get <workbook_id>` | `datalens_workbooks_get` |
| Several workbooks by id | `uv run ycli datalens workbooks list-by-ids <id> <id>…` | `datalens_workbooks_list_by_ids` |
| What a workbook holds | `uv run ycli datalens workbooks entries-list <workbook_id> [--scope dash] [--scope dataset] [--all]` | `datalens_workbooks_entries_list` |
| Who has which role on a workbook | `uv run ycli datalens workbooks access-bindings-list <workbook_id>` | `datalens_workbooks_access_bindings_list` |
| Find entries anywhere (give a scope or ids) | `uv run ycli datalens entries list --scope dash [--filters '{"name": "sales"}'] [--all]` | `datalens_entries_list` |
| What an entry uses, or what uses it | `uv run ycli datalens entries relations-list <entry_id>… --link-direction from\|to` | `datalens_entries_relations_list` |
| Revisions of an entry | `uv run ycli datalens entries revisions-list <entry_id>` | `datalens_entries_revisions_list` |
| What you may do with entries | `uv run ycli datalens entries permissions-get <entry_id>…` | `datalens_entries_permissions_get` |
| What you may do with many entries, workbooks and collections | `uv run ycli datalens permissions get-bulk --entry-id … --workbook-id … --collection-id …` | `datalens_permissions_get_bulk` |
| How far an export of a workbook is | `uv run ycli datalens workbookexports status-get <export_id>` | `datalens_workbookexports_status_get` |
| The exported workbook, as one document | `uv run ycli datalens workbookexports result-get <export_id>` | `datalens_workbookexports_result_get` |
| How far an import is | `uv run ycli datalens workbookimports status-get <import_id>` | `datalens_workbookimports_status_get` |
| Keys for embedding of a workbook (never the private key) | `uv run ycli datalens embeddingsecrets list <workbook_id>` · `get <embedding_secret_id>` | `datalens_embeddingsecrets_list` · `datalens_embeddingsecrets_get` |
| Where an entry is embedded | `uv run ycli datalens embeds list <entry_id>` | `datalens_embeds_list` |
| Who has which role on a shared entry | `uv run ycli datalens sharedentries access-bindings-list <entry_id> [--get-inherited-bindings]` | `datalens_sharedentries_access_bindings_list` |
| Entries changed in a period (deleted ones too) | `uv run ycli datalens audit entries-updates-list --from 2026-10-01T00:00:00Z [--to …] [--all]` | `datalens_audit_entries_updates_list` |
| What one user may do with entries | `uv run ycli datalens audit entry-permissions-get <entry_id>… --user-id <user_id>` | `datalens_audit_entry_permissions_get` |
| One saved SQL query (experimental) | `uv run ycli datalens sqlqueries get <sql_query_id>` | `datalens_sqlqueries_get` |
| Who holds a licence (a seat) | `uv run ycli datalens licensing licenses-list [--status active] [--user-ids <id>]… [--all]` | `datalens_licensing_licenses_list` |
| How many licences there may be, and how many are active | `uv run ycli datalens licensing limit-get` | `datalens_licensing_limit_get` |
| The cloud environments of the instance (experimental) | `uv run ycli datalens cloudenvironments list [--filter 'status="READY"'] [--all]` · `get <id>` | `datalens_cloudenvironments_list` · `datalens_cloudenvironments_get` |
| What a cloud environment's bucket holds (experimental) | `uv run ycli datalens cloudenvironmentstorage bucket-objects-list <cloud_environment_id> [--prefix …]` · `bucket-object-metadata-get <id> --path …` | `datalens_cloudenvironmentstorage_bucket_objects_list` · `…_bucket_object_metadata_get` |
| The REST catalogs of the instance (experimental) | `uv run ycli datalens restcatalogs list [--cloud-environment-id <id>] [--all]` | `datalens_restcatalogs_list` |
| How far a Lakehouse operation is (experimental) | `uv run ycli datalens lakehouseoperations get <operation_id>` | `datalens_lakehouseoperations_get` |
| The Trino clusters of the instance (experimental) | `uv run ycli datalens trinoclusters list [--collection-id <id>] [--all]` · `get <id>` | `datalens_trinoclusters_list` · `datalens_trinoclusters_get` |
| The sizes a Trino cluster's machines may have (experimental) | `uv run ycli datalens trinoclusters resource-presets-list <cloud_environment_id>` · `resource-preset-get <id> --cloud-environment-id <id>` | `datalens_trinoclusters_resource_presets_list` · `…_resource_preset_get` |
| The applications of a Spark cluster, and the log of one (experimental) | `uv run ycli datalens sparkapplications list <cluster_id>` · `get <cluster_id> --application-id <id>` · `log-list <cluster_id> --application-id <id> [--page-token …]` | `datalens_sparkapplications_list` · `…_get` · `…_log_list` |
| Users, groups and service accounts (to give a role to) | `uv run ycli datalens members list [--search …] [--tab-id GROUP] [--all]` | `datalens_members_list` |
| One connection (never its password or token) | `uv run ycli datalens connections get <connection_id>` | `datalens_connections_get` |
| One dataset: sources, joins, fields with their guids | `uv run ycli datalens datasets get <dataset_id>` | `datalens_datasets_get` |
| Rows of a dataset (one page) | `uv run ycli datalens datasets data-get <dataset_id> --columns <guid> --columns <guid> [--limit 100] [--offset 100 --sort '{"guid": "…", "direction": "asc"}']` | `datalens_datasets_data_get` |
| Check a dataset or a change to it, saving nothing | `uv run ycli datalens datasets validate <dataset_id> --body-file change.json` | `datalens_datasets_validate` |
| The data a saved chart shows, as tables | `uv run ycli datalens charts data-get <chart_id> [--params '{"year": "2026"}']` | `datalens_charts_data_get` |
| One chart, by how it is built | `uv run ycli datalens charts wizard get <chart_id> --branch saved` · `charts ql get <chart_id> --branch saved` · `charts editor get <chart_id> --branch saved` | `datalens_charts_wizard_get` · `datalens_charts_ql_get` · `datalens_charts_editor_get` |
| One report: its slides and what stands on them | `uv run ycli datalens reports get <entry_id>` | `datalens_reports_get` |
| One dashboard (large: write it to a file) | `uv run ycli -o json datalens dashboards get <dashboard_id> --branch saved > dash.json` | `datalens_dashboards_get` |
| Spark clusters, one of them, the sizes an instance can take (experimental, not measured) | `uv run ycli datalens sparkclusters list` · `sparkclusters get <cluster_id>` · `sparkclusters resource-presets-list --cloud-environment-id <id>` · `sparkclusters resource-presets-get <preset_id> --cloud-environment-id <id>` | `datalens_sparkclusters_list` · `datalens_sparkclusters_get` · `datalens_sparkclusters_resource_presets_list` · `datalens_sparkclusters_resource_presets_get` |
| One HTML page (not its HTML), and a temporary link that shows it | `uv run ycli datalens htmlpages get <entry_id> --branch published` · `htmlpages preview-url-get <entry_id> --branch saved` | `datalens_htmlpages_get` · `datalens_htmlpages_preview_url_get` |

**`workbooks list` does not descend.** It lists one collection (the root by default); to find a workbook anywhere, walk `collections content-list`.

**Saving a report through the API loses part of it (measured, 2026-10-06).** `reports update` and `reports create` do not keep the `layout` of the elements of a slide (it comes back `null`) and drop part of `settings` (`autoupdateInterval`, `globalParams`, `loadPriority`, `maxConcurrentRequests`, `silentLoading`), `showInTOC` of an element and `autoHeight` of a tab: DataLens drops them without a word, though ycli sends them. A report saved this way loses where its elements stood. Do not update an existing report without telling the person first; a dashboard has no such loss.

**An entry's `scope` is its kind**: `connection`, `dataset`, `widget` (a chart), `dash`, `report`. `entries-list` takes `--order-by '{"field": "name", "direction": "asc"}'` and `--filters '{"name": "sales"}'` as JSON objects.

**Content is mixed.** `content-list` returns collections, workbooks and entries in one list; `entity` says which (`collection`, `workbook`, `entry`); a kind DataLens adds later comes as it is, with its own `entity`. The root has no id: leave the id out (MCP: `collection_id` null).

---

## 3. Writing

An operation takes the fields of its request as arguments, under one name on every surface: `--parent-id` in the CLI, `parent_id` in a tool and in the SDK.

| Operation | CLI | MCP tool |
|-----------|-----|----------|
| Create a collection | `uv run ycli datalens collections create --title … [--parent-id <id>] [--description …]` | `datalens_collections_create` |
| Rename or describe | `uv run ycli datalens collections update <collection_id> [--title …] [--description …]` | `datalens_collections_update` |
| Move one | `uv run ycli datalens collections move <collection_id> [--parent-id <id>] [--title …]` | `datalens_collections_move` |
| Move several | `uv run ycli datalens collections move-bulk <id> <id>… [--parent-id <id>]` | `datalens_collections_move_bulk` |
| Delete one | `uv run ycli datalens collections delete <collection_id>` | `datalens_collections_delete` |
| Delete several | `uv run ycli datalens collections delete-bulk <id> <id>…` | `datalens_collections_delete_bulk` |
| Give or take away roles | `uv run ycli datalens collections access-bindings-update <collection_id> --delta '<json>'…` | `datalens_collections_access_bindings_update` |
| Create a workbook | `uv run ycli datalens workbooks create --title … [--collection-id <id>] [--description …]` | `datalens_workbooks_create` |
| Rename or describe a workbook | `uv run ycli datalens workbooks update <workbook_id> [--title …] [--description …]` | `datalens_workbooks_update` |
| Move one or several workbooks | `uv run ycli datalens workbooks move <workbook_id> [--collection-id <id>]` · `move-bulk <id> <id>…` | `datalens_workbooks_move` · `datalens_workbooks_move_bulk` |
| Delete one or several workbooks | `uv run ycli datalens workbooks delete <workbook_id>` · `delete-bulk <id> <id>…` | `datalens_workbooks_delete` · `datalens_workbooks_delete_bulk` |
| Give or take away roles on a workbook | `uv run ycli datalens workbooks access-bindings-update <workbook_id> --delta '<json>'…` | `datalens_workbooks_access_bindings_update` |
| Start exporting a workbook | `uv run ycli datalens workbookexports start <workbook_id>` | `datalens_workbookexports_start` |
| Stop an export | `uv run ycli datalens workbookexports cancel <export_id>` | `datalens_workbookexports_cancel` |
| Make a workbook from an export | `uv run ycli datalens workbookimports start --body-file export.json --title … [--collection-id <id>]` | `datalens_workbookimports_start` |
| Make a key for embedding (prints the private key, once) | `uv run ycli -o json datalens embeddingsecrets create --title … --workbook-id <id> > secret.json` | `datalens_embeddingsecrets_create` |
| Delete a key for embedding | `uv run ycli datalens embeddingsecrets delete <embedding_secret_id>` | `datalens_embeddingsecrets_delete` |
| Embed an entry | `uv run ycli datalens embeds create --title … --embedding-secret-id <id> --entry-id <id> --public-params-mode --settings '{}'` | `datalens_embeds_create` |
| Save an embed as given | `uv run ycli datalens embeds update <embed_id> --title … --embedding-secret-id <id> --no-public-params-mode --settings '{}' [--unsigned-params …]` | `datalens_embeds_update` |
| Delete an embed | `uv run ycli datalens embeds delete <embed_id>` | `datalens_embeds_delete` |
| Give or take away roles on a shared entry | `uv run ycli datalens sharedentries access-bindings-update <entry_id> --delta '<json>'…` | `datalens_sharedentries_access_bindings_update` |
| Save a SQL query in a workbook (experimental) | `uv run ycli datalens sqlqueries create --workbook-id <id> --name … --connection-id <id> --query '…'` | `datalens_sqlqueries_create` |
| Save a SQL query anew | `uv run ycli datalens sqlqueries update <sql_query_id> --connection-id <id> --query '…'` | `datalens_sqlqueries_update` |
| Run a saved SQL query | `uv run ycli datalens sqlqueries run <sql_query_id> [--params '{"since": "2026-10-01"}']` | `datalens_sqlqueries_run` |
| Delete a saved SQL query | `uv run ycli datalens sqlqueries delete <sql_query_id>` | `datalens_sqlqueries_delete` |
| Give users a licence (billed; not measured) | `uv run ycli datalens licensing licenses-assign <user_id>…` | `datalens_licensing_licenses_assign` |
| Set how many licences there may be (billed; not measured) | `uv run ycli datalens licensing limit-set <value>` | `datalens_licensing_limit_set` |
| Rename an entry | `uv run ycli datalens entries rename <entry_id> --name …` | `datalens_entries_rename` |
| Create a connection | `uv run ycli datalens connections create --body-file conn.yaml` | `datalens_connections_create` |
| Change a connection | `uv run ycli datalens connections update <connection_id> --data '{"host": "db2"}'` | `datalens_connections_update` |
| Delete a connection | `uv run ycli datalens connections delete <connection_id>` | `datalens_connections_delete` |
| Create a dataset (empty is valid) | `uv run ycli datalens datasets create --name … --workbook-id <id> --dataset '{"sources": [], "result_schema": []}'` | `datalens_datasets_create` |
| Save a dataset as given | `uv run ycli datalens datasets update <dataset_id> --body-file dataset.json` | `datalens_datasets_update` |
| Delete a dataset | `uv run ycli datalens datasets delete <dataset_id>` | `datalens_datasets_delete` |
| Create a chart | `uv run ycli datalens charts wizard create --workbook-id <id> --name … --body-file chart.json` · `charts ql create --template ql …` · `charts editor create --body-file chart.json` | `datalens_charts_wizard_create` · `datalens_charts_ql_create` · `datalens_charts_editor_create` |
| Save a chart as given | `uv run ycli datalens charts wizard update <chart_id> --mode save --body-file chart.json` · `charts ql update <entry_id> --template ql --mode save …` · `charts editor update --mode save --body-file chart.json` | `datalens_charts_wizard_update` · `datalens_charts_ql_update` · `datalens_charts_editor_update` |
| Delete a chart | `uv run ycli datalens charts wizard delete <chart_id>` · `charts ql delete` · `charts editor delete` | `datalens_charts_wizard_delete` · `datalens_charts_ql_delete` · `datalens_charts_editor_delete` |
| Create a report (at least one slide) | `uv run ycli datalens reports create --workbook-id <id> --name … --meta null --body-file report.json` | `datalens_reports_create` |
| Save a report (loses the layout of slide elements: ask first) | `uv run ycli datalens reports update <entry_id> --mode save --body-file report.json` | `datalens_reports_update` |
| Delete a report | `uv run ycli datalens reports delete <entry_id>` | `datalens_reports_delete` |
| Create a dashboard | `uv run ycli datalens dashboards create --body-file dash.json` | `datalens_dashboards_create` |
| Save a dashboard as given | `uv run ycli datalens dashboards update --mode save --body-file dash.json [--lock-token …]` | `datalens_dashboards_update` |
| Delete a dashboard | `uv run ycli datalens dashboards delete <dashboard_id>` | `datalens_dashboards_delete` |
| Create, start, stop, delete a Spark cluster (paid for while it runs: only when asked; experimental, not measured) | `uv run ycli datalens sparkclusters create --collection-id <id> --cloud-environment-id <id> --name … --config '{…}'` · `sparkclusters start <cluster_id>` · `sparkclusters stop <cluster_id>` · `sparkclusters delete <cluster_id>` | `datalens_sparkclusters_create` · `datalens_sparkclusters_start` · `datalens_sparkclusters_stop` · `datalens_sparkclusters_delete` |
| Create an HTML page | `uv run ycli datalens htmlpages create --workbook-id <id> --name … --content '<p>…</p>'` | `datalens_htmlpages_create` |
| Save new HTML of a page, or make a revision current (one of the two) | `uv run ycli datalens htmlpages update <entry_id> --mode save --content '…'` · `htmlpages update <entry_id> --mode publish --rev-id <rev>` | `datalens_htmlpages_update` |
| Delete an HTML page | `uv run ycli datalens htmlpages delete <entry_id>` | `datalens_htmlpages_delete` |
| Lock an entry for editing | `uv run ycli datalens entrylocks create <entry_id> --data '{"duration": 300000}'` | `datalens_entrylocks_create` |
| Hold a lock longer | `uv run ycli datalens entrylocks extend <entry_id> --data '{"lockToken": "…", "duration": 600000}'` | `datalens_entrylocks_extend` |
| Release a lock | `uv run ycli datalens entrylocks delete <entry_id> --params '{"lockToken": "…"}'` | `datalens_entrylocks_delete` |

**No parent is the root.** Leave `--parent-id` / `parent_id` (a collection) or `--collection-id` / `collection_id` (a workbook) out to create in the root or to move there: `move <id>` with no destination moves it to the root.

**A workbook is exported and imported in steps.** `workbookexports start` answers an export id at once; ask `workbookexports status-get` until `status` is `success` (`pending` before, `error` if it failed), then `workbookexports result-get`. Its `data` (the `export` and its `hash`, together) is what `workbookimports start` takes: `… result-get <export_id> | jq '{data}' > export.json`, then `workbookimports start --body-file export.json --title …`. The new workbook exists at once and is filled as the import runs; `workbookimports status-get` says when it is done. A cancelled export ends with the status `error` and the notification `WORKBOOK_EXPORT_CANCELLED`; cancelling one that is over changes nothing. The result of an export that is not over, or was cancelled, answers 409; an id nothing knows answers 404.

**After an import, give the connections their secrets again.** A password or a token is not in the exported document: the status of the export and of the import carries a notification for each connection (`NOTIF.WB_EXPORT.CONN.CHECK_CREDENTIALS`, `NOTIF.WB_IMPORT.CONN.CHECK_CREDENTIALS`), and the imported connection works once `connections update` has given it the secret.

**Write the exported document to a file, do not read it.** A workbook with a dashboard exports to hundreds of kilobytes (287 KB for 27 entries, measured): redirect `workbookexports result-get` to a file and hand the file to `workbookimports start --body-file`; an agent that takes the document into its context spends it on nothing.

**A shared entry lies in a collection, not in a workbook.** A connection or a dataset created with `--collection-id` (and no `--workbook-id`) is one: workbooks may use it, and it has roles of its own, `datalens.sharedEntries.*` (`admin`, `viewer`), changed by deltas as on a collection. `sharedentries access-bindings-list` of an entry that lies in a workbook, or of an id nothing knows, answers an empty list, not an error. A change of roles answers an operation that may not be done yet (`done: false`): read the roles again to see it.

**The audit is asked with a start time.** `audit entries-updates-list` requires `--from` (ISO-8601 with its zone) and lists every entry changed since, deleted ones included (`isDeleted`), with who changed it. `audit entry-permissions-get` answers by entry id: `permissions` (`execute`, `read`, `edit`, `admin`), or `error` for an entry that does not exist; the user's id is the one `createdBy` of an entry gives.

**Cloud environments are experimental, and all but their listing is not measured.** A cloud environment is a cloud and a subnet DataLens runs clusters in, with a storage bucket. `cloudenvironments list` is measured (an instance with none answers an empty list; a filter is `field="value"` over `name`, `cloud_id`, `status`, `created_by_id`, the quotes included). `cloudenvironments create`, `update` and `delete` make and change resources in a cloud, which may be billed: they are written from the published document and were never called; ask the person before any of them. Each answers an operation that is not done yet. The four `cloudenvironmentstorage` commands (the paths in the bucket, the size of an object, a signed link to read or to put one) are written from the document too; a signed link works for whoever holds it. An id nothing knows answers 403 Permission denied, not 404: it is not a lack of rights.

**Spark applications are experimental, and not measured.** Every command takes the Spark cluster (without it the API answers 400; a cluster nothing knows answers 403, not 404), and the owner's instance has none, so the section is written from the published document. `sparkapplications log-list` answers one fragment of the log and the token of the next: give it back as `--page-token` to read on. `sparkapplications create` takes exactly one of three kinds, `--spark-application` (a JAR), `--pyspark-application` (a Python file) or `--spark-connect-application`, each a JSON object; over MCP the kind is the field of `body` that holds the application (`sparkApplication`, `pysparkApplication`, `sparkConnectApplication`). `create` and `cancel` were never called: ask the person before either.

**Trino clusters are experimental, and billed while they run.** `trinoclusters list` is measured (an instance with none answers an empty list). Everything else is written from the published document and was never called: `create`, `start`, `stop`, `delete`, `catalog-create` and `catalog-delete` make or change cloud resources; ask the person before any of them. Each answers an operation to follow with `lakehouseoperations get`. The resource presets are read for a cloud environment, which is required (without it the API answers 400). An id nothing knows answers 403 Permission denied, not 404; a collection nothing knows, given to `list`, answered 500.

**REST catalogs and Lakehouse operations are experimental too.** `restcatalogs list` is measured (an instance with none answers an empty list). `restcatalogs create` makes a bucket in a cloud, which may be billed: written from the document, never called; ask the person first. It answers an operation, as making a cloud environment does: `lakehouseoperations get <operation_id>` says whether it is `done`, and then its `error` or its `response`.

**A licence is a seat DataLens bills for.** Yandex's pricing counts the seats of the instance (the number of seats times the cost of one), so `licensing licenses-assign` and `licensing limit-set` change what the organization pays: ask the person before either. Both are written from the published document and were never called. The reads are measured: `licenses-list` answers whose each licence is, its type (`creator` or `viewer`) and whether it is active; `limit-get` answers the limit in force with the count of active licences, and `next: null` when no change is set.

**Saved SQL queries are experimental, and not measured.** DataLens marks the whole section experimental; ycli wraps it from the published document, and no reply of it was checked against the service. An organization whose SQL editor is off answers `403 SQL_EDITOR_NOT_ALLOWED` to every call. A query runs over a connection to PostgreSQL, ClickHouse, MySQL, Greenplum or Trino; `sqlqueries run` runs the text as it is saved, so a text that changes data changes it. `sqlqueries update` takes the connection and the text every time.

**The private key of a key for embedding is given once.** `embeddingsecrets create` answers the id and the private key; `get` and `list` never return the key again, so write it to a file at once (`-o json … > secret.json`, a file nobody else reads) and do not paste it anywhere. Through MCP the key comes in the tool's result, into the agent's context: hand it over at once and do not repeat it.

**An embed is saved whole.** `embeds update` replaces the embed: the API requires the title, the key, the mode of parameters and the settings every time, and a list left out (`--deps-ids`, `--unsigned-params`, `--private-params`) is saved empty. Read the embed with `embeds list` first and name what is to stay. Deleting an embed twice answers 404.

**Deleting a collection or a workbook deletes what it holds**: nested collections, workbooks and their entries. The reply lists what was deleted.

**Roles change by deltas.** `access-bindings-update` does not replace the list: each delta adds or removes one role of one subject, and the roles it does not name stay.

```json
{"action": "ADD", "accessBinding": {"roleId": "datalens.collections.viewer", "subject": {"id": "<user id>", "type": "userAccount"}}}
```

The subject's `id` is the `sub` of a member (`members list`). `action` is `ADD` or `REMOVE`; subject `type` is one of `userAccount`, `federatedUser`, `serviceAccount`, `group`, `invitee`, `system`. It answers with an operation; `done` says whether it has been applied.

**A lock is held by its token.** `entrylocks create` answers with the token alone: keep it, `extend` and `delete` take it. The duration is in milliseconds. An entry that is already locked answers 423 `ERR.US.ENTRY_IS_LOCKED` with who holds the lock and until when; releasing an entry that is not locked answers 404.

**Permissions come as a map by id.** `entries permissions-get` and `permissions get-bulk` answer `{<id>: {"permissions": {…}}}`; an id that does not exist answers `{<id>: {"error": "NOT_FOUND"}}` in the same map, and an id of a wrong form refuses the whole request. `entries list` needs `--scope`, `--scopes` or `--id`; an entry you may not read comes with `isLocked: true` and little else.

**A connection is its kind.** `type` (`clickhouse`, `postgres`, `gsheets`, `json_api`… 29 kinds) says which fields it takes; over MCP read them with `schema_get(service="datalens", name="ConnectionCreate")`, then the definition of the kind. `connections get` answers with the kind in `db_type` and never with the password or the token. A connection to Google Sheets cannot be created through the API (`type: gsheets` answers 400 "This connection type is not editable"): make it in the DataLens interface, where its kind is `gsheets_v2`, then read it and build datasets on it here.

**Give a secret in a file.** A password or a token comes from a file outside the repository, mode 600: in `--body-file`, or as one field with `-F password=@secret.txt`. Typed after `-F` or in `--data` it stays in the shell history. Write the file of one field with no line break at its end (`printf %s 'secret' > secret.txt`), or the break goes out with the secret. `--dry-run` prints a secret as `***`, and a model prints it as `**********`; only the request itself carries it.

**A dataset is changed whole.** Read it with `datasets get`, change `dataset` (sources, `result_schema`, filters), and send it back as `data.dataset` of `datasets update`; `--body-file` holds it under `data`. Try the change with `datasets validate` first: it saves nothing and answers `code`, `message` and `dataset_errors`. Read the dataset again after every save: content of an older revision is refused (`ERR.DS_API.DATASET_REVISION_MISMATCH`). A source or a field of a kind ycli does not know comes and goes back as it is. Over MCP the body is read with `schema_get(service="datalens", name="DatasetUpdate")`.

**Rows are asked for by guid.** `datasets data-get` takes the guids of fields (`dataset.result_schema[].guid`), not their titles. One call is one page: `--limit` rows (100 by default) from `--offset`, and an offset above zero needs `--sort`, or the API refuses the request.

**A chart is read by how it is built.** An entry of the scope `widget` is a chart, and its `type` says which command reads it: `…_wizard_node` is `charts wizard`, `…_ql_node` is `charts ql`, the rest (`table_node`, `d3_node`, `markdown_node`, `advanced-chart_node`, `control_node`) is `charts editor`. A chart is changed whole, like a dataset: read it, change `entry.data`, send it back with `--mode save` (a draft) or `--mode publish`. `--body-file` gives the request itself (`data`, `workbookId`, `name`), and a flag lies over it. Over MCP the content of a wizard chart is read with `schema_get(service="datalens", name="WizardChartData")`. QL charts take `--template ql`, the only value the API accepts today, and come flat, with no `entry` around them.

**A dashboard is large and changed whole.** A real one is 100 KB and more, which may be over what a client shows of a tool's reply: read a big one into a file with the CLI and work on the file. To change it, read it, change `entry.data` (tabs, and the charts, selectors and texts on them) and send it back in `--body-file` as `{"entry": {"entryId": …, "data": …, "meta": …, "revId": …}}` with `--mode save` or `--mode publish`. A new dashboard needs `counter`, `salt`, `settings` and `tabs` in its `data`; a tab may be empty. Over MCP the entry is read with `schema_get(service="datalens", name="DashboardUpdate")`.

**A read names its version: `--branch` or `--rev-id`, exactly one.** An entry has two versions, the saved one and the published one, and a save (`update --mode save`) writes the saved one. The reads of a chart, a dashboard and an HTML page (`charts wizard get`, `charts ql get`, `charts editor get`, `dashboards get`, `htmlpages get`, `htmlpages preview-url-get`) take `--branch saved` or `--branch published`, or one revision with `--rev-id`; with neither, or with both, ycli refuses before sending (`give exactly one of: branch, rev_id`). To change an entry, read `--branch saved`: the published content sent back would overwrite what was saved after it. Measured, 2026-10-07: DataLens itself answers the published version when neither is named, and a named revision whatever the branch says, which is why ycli asks. `reports get` has no branch in the API and answers the saved version.

**A revision does not guard a save (measured, 2026-10-07).** `update` of a chart, a dashboard and a report answers 200 with a revision that is out of date, with the revision of another entry, and with none, and overwrites what was saved; only an id of a wrong form is refused (400), and a QL chart does not look at it at all. A dataset alone is guarded: content read from an older revision answers 400 `DATASET_REVISION_MISMATCH`. Two writers of one chart or dashboard overwrite each other: read right before you save, and keep the gap short.

**A delete is final and leaves the id behind (measured, 2026-10-07).** The API has no operation that restores an entry, a workbook or a collection; what was deleted answers 404. A delete is not refused because something uses the entry: a chart goes on naming its deleted dataset or connection, and a dashboard its deleted chart. Deleting a workbook deletes every entry in it. Look at `entries relations-list <entry_id> --link-direction to` before deleting, and ask the person.

**A name is unique in a workbook among entries of one kind (measured, 2026-10-07).** A second dataset, a second connection or a second chart of a name that is taken answers 400 `The entity already exists` (a wizard chart and an editor chart share their names); a dataset may be named as a connection is. The name of a deleted entry is free again.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.