npx skills add ...
npx skills add exploreomni/omni-agent-skills --skill omni-admin
Administer an Omni Analytics instance — manage connections, users, groups, user attributes, permissions, schedules, and schema refreshes via the Omni CLI. Use this skill whenever someone wants to manage users or groups, set up permissions on a dashboard or folder, configure user attributes, create or modify schedules, manage database connections, refresh a schema, set up access controls, provision users, or any variant of "add a user", "give access to", "set up permissions", "who has access", "configure connection", "refresh the schema", or "schedule a delivery".
npx skills add exploreomni/omni-agent-skills --skill omni-admin
Manage your Omni instance — connections, users, groups, user attributes, permissions, schedules, and schema refreshes.
Tip: Most admin endpoints require an Organization API Key (not a Personal Access Token).
Auth: a profile authenticates with an API key or OAuth. If
whoami(or any call) returns 401, hand off — ask the user to run! omni config login <profile>(OAuth 2.1 browser flow; it blocks ~2 min on the browser). Don't runconfig loginyourself in a headless/CI session (no browser → timeout); on a local interactive machine you may. See theomni-api-conventionsrule for profile setup (omni config init --auth oauth) and discovering command and request-body shapes with--schema.
If no CLI profile exists but the environment provides credentials, pass them explicitly:
Tip: Use
-o jsonto force structured output for programmatic parsing, or-o humanfor readable tables. The default isauto(human in a TTY, JSON when piped).
VIEWER, EXPLORER, EDITOR, MANAGER) when updating content access.Rotating invalidates the previous key — confirm with the user before running, and re-register the new public key wherever the old one was trusted.
The
--bodyblocks below are worked examples. For the authoritative field list (types, required, enums), run the command with--schema— e.g.omni scim users-create --schema— rather than relying on these shapes to be exhaustive.
User attributes work with access_filters in topics for row-level security.
SCIM can set values only for attribute definitions that already exist. Use
omni user-attributes list to confirm the requested attribute definition exists
before setting a value, but do not use it as proof that a specific user's value
changed. If the definition is missing, report that it must be created in
Admin -> User Attributes before values can be assigned; do not keep retrying
SCIM paths or claim the value was set from an empty User attributes set: {}
response.
When the user explicitly asks to set or update a user attribute, converge the
user record with a SCIM update even if the initial user lookup already shows the
requested value. This keeps the operation idempotent while still honoring the
requested admin action. After the update, read back the same user and verify the
value under urn:omni:params:1.0:UserAttribute.
This is the canonical access check other skills defer to (e.g. omni-content-builder / omni-model-builder deciding whether a new field goes on a branch vs a workbook model). Run omni whoami whoami --model-id <modelId> and read rolesByModel[<id>].permissions. Gate on the presence of permissions, not the role name — names can be renamed custom roles and surface as internal codes (e.g. QUERY_TOPICS):
Permission (in whoami) | Capability |
|---|---|
QUERY_TOPICS | query curated topics (Restricted Querier and up) |
QUERY_FULL_MODEL | full-model + SQL access — and the observable proxy for "can create/use a branch" (Querier, Modeler, Admin) |
UPDATE (shared-model-scoped) | merge/promote changes to the shared model (Modeler, Admin) |
USE_WORKBOOKS | create content (workbooks/dashboards). A Viewer lacks this and cannot author at all. |
Decision shortcuts:
QUERY_FULL_MODEL present → a shared-model branch (merge it yourself if you also have UPDATE, otherwise open a PR / request a merge — a Querier can branch and modify but not promote); QUERY_FULL_MODEL absent but USE_WORKBOOKS present (Restricted Querier) → the document's workbook model (extension). A Viewer can't author content, so they never reach this choice.QUERY_FULL_MODEL on a shared-model branch. So don't plan a topic-scope, join, or grant change for a restricted querier's workbook model; it 403s mid-build and can leave the document half-modeled.QUERY_TOPICS without QUERY_FULL_MODEL means every query they author must be topic-based (table = the topic's base view + join_paths_from_topic_name). A bare base-view query or a raw-SQL userEditedSQL tile needs QUERY_FULL_MODEL (full-model + SQL access) — so it isn't an option for a restricted-querier author; build every tile on a topic. (Distinct from visibility: even a Querier-authored non-topic tile is hidden from restricted/Viewer audiences unless Access-Boosted.)whoami does not list branch ability as its own entry — branch create/use is a separate capability granted to Querier+ — so use QUERY_FULL_MODEL as the proxy. (Holds for base roles; a custom role could grant one without the other — confirm when it matters.)Resolving another user's membershipId needs the org key.
whoami → user.membershipIdis self-only. For someone else,omni scim users-list --filter 'userName eq "them@company.com"'returns the membership as itsid(which is the membershipId — not the user'suser.id). But the SCIM API accepts only the org-level API key: a user-scoped PAT/OAuth is rejected with "User-scoped API keys are not allowed to access the SCIM API." Theget/assign-model-rolecalls above work with a user PAT — only this lookup needs the org key.
roleName (not role), and the path id is the membership id (a user id returns 404).roleName is a server-validated, instance-specific string — base roles (e.g. QUERY_TOPICS, QUERIER, CONNECTION_ADMIN) plus any org custom roles. The valid set is not discoverable via --schema (the field is a bare string, no enum) or any list command; an unknown value returns 422 "Invalid role". Discover a valid code by reading get-model-roles on a membership that already holds the target role.role is one of NO_ACCESS, VIEWER, EDITOR, MANAGER.
Access Boost lets Viewer / Restricted Querier roles view a dashboard built on non-topic content — a raw-SQL (userEditedSQL) tile or a bare base-view query — which those roles otherwise can't see. (Model access grants still apply unless the grant sets access_boostable: true.)
Dashboard-only: Access Boost lifts the restriction on the dashboard view of those tiles. It does not extend to the underlying workbook — a restricted role still can't open the workbook's non-topic or SQL tabs (or see the query behind the tile) regardless of Access Boost.
⚠️ Confirm before boosting — it loosens access controls. Access Boost deliberately exposes content that restricted roles can't otherwise see, and non-topic / raw-SQL tiles bypass topic-scoped governance (access filters, always_where) — so boosting can surface data those controls would normally withhold. Do not apply Access Boost autonomously or as a reflexive fix for "they can't see it." First:
add-permits) over the org-wide organizationAccessBoost; reach for org-wide only when that's explicitly what's wanted.access_boostable: true; don't treat that as a safety net, confirm intent regardless.Prerequisite (org capability, not in the CLI): the org must have allowsDocumentAccessBoost enabled (and allowsMemberToProvisionAccessBoost for non-admins to grant it). This is an instance/admin setting — if it's off, the document-level flags below are silently cleared. It's a gate; it does not itself turn Access Boost on anywhere.
Once you've confirmed intent, there are two activation levers, both scoped to a single document:
update-permission-settings (PUT) also carries the document's other toggles — canDownload, canDrill, canSchedule, canUpload, canUseDashboardAi, canUseTimezoneOverride, canViewWorkbook, requirePullRequestToPublish. Note organizationAccessBoost boosts the org-default principal on this document only — it is not an org-wide switch.
Read and manage AI credit controls and usage (entity-group commands and usage reads require CLI ≥ 1.1.2). Org-level controls require the AI-admin permission; per-user controls and usage require manage-user-attributes; entity-group controls and usage require add/remove-users. Per-user and per-entity-group limits are also behind instance feature flags.
Gotcha:
credit-usage-users-readtakes membership ids (the user's membership in this organization), not base user ids — an unknown id 404s the whole request, naming the offending id. At most 1000 ids per request, no duplicates; users with no usage report 0.
Manage CSV/spreadsheet uploads (the files users upload to query alongside warehouse data). create and replace-data are multipart file uploads: pass the CSV path with --file and the other fields as flags. Run either with --schema for the full field list. (On CLI < 1.2.0 these flags don't exist — the same fields go through --body as multipart fields, with file paths as the binary values.)
replace-data fully replaces the upload's data while its id stays stable — views and document tabs reference the upload by id, so they serve the new data with no model or document changes. Column renames/removals may break content referencing the old columns, so compare headers before replacing. For uploads list --model-id: shared models return connection uploads; workbook models return their own uploads.
Flags vs.
--body:--filetakes a path, not file contents, and--branch-id/--branch-nameare mutually exclusive.--fileand--model-idare required oncreate(--fileonreplace-data) unless you supply the same fields through--body, which on these two commands carries multipart fields — binary values are still file paths, not inline data.
Admin operations can silently fail or partially apply. Always read back the state after any write to confirm the change took effect.
Check that: active matches what you set, displayName is correct, and the user ID was returned (not an error).
Check that: the group exists with the expected displayName, and members array contains the expected user UUIDs.
Check that: the principal is listed and the role matches what you set (VIEWER, EDITOR, etc.).
Check that: the response contains the target user, the user's
urn:omni:params:1.0:UserAttribute object includes the requested attribute name,
and the value exactly matches what you set. omni user-attributes list only
verifies that the attribute definition exists.
If the attribute is used for row-level security (access_filters), test it by running a query as the target user:
Verify the results are correctly filtered — the user should only see rows matching their attribute value.
Check that: the created schedule id appears in the list and the returned fields match the requested schedule cron, timezone, destinationType, content, format, and dashboard identifier. If the list/get response shape is not parseable, report that schedule setting verification was inconclusive instead of silently treating an empty parser result as success. Always verify recipients with recipients-get.
| Operation | Verify With | What to Check |
|---|---|---|
| Create/update user | omni scim users-list --filter ... | User exists, active status correct |
| Create/update group | omni scim groups-list | Group exists, members list correct |
| Set document permissions | omni documents get-permissions | Access level and target correct |
| Set folder permissions | omni folders get-permissions | Access level and target correct |
| Set user attribute | omni scim users-list --filter ... | User attribute extension contains requested value |
| User attribute + access filter | omni query run with userId | Row-level filtering works |
| Create schedule | omni schedules list | Schedule settings correct |
| Add recipients | omni schedules recipients-get | All recipients listed |