arkushHelp

For organizations

Administer an instance

This guide is for the admin of an arkush instance, which is most often an org install. Each section covers one task. It says what the admin changes in the app, what the operator changes in the environment file, and what the app shows when nothing is configured.

On arkush.app, the admins are the people who run arkush.app. A person who signs in there holds no admin right, and the Administration areas do not show.

Two roles share an instance. The admin works inside the app, in Administration. The operator runs the service: the host, the environment file, and the files beside the database. One person can hold both roles.

Before you start

The admin right comes from ARKUSH_ADMINS in the environment file. A person who signs in with an address on that list has three ways in:

Administration is divided into areas, one per job. A panel on the left lists them, and each one has its own address. An area holds one or more sections. For example, the Access area holds a Rights section and a Groups section.

Open /admin itself for the index. It lists the areas. Above them, it counts each problem on the instance that needs attention, with a button to the area that fixes it. When nothing needs attention, the index lists the areas only.

The Administration index, three parts marked with numbers. 1 marks the panel on the left that lists the seven areas. 2 marks a banner that counts 2 datasources with no service account, with an Open Credentials button. 3 marks the list of the areas, each with one line that says what it holds.
The Administration index: (1) the panel of areas, (2) a problem that needs attention, with the button to the area that fixes it, (3) the areas.

The split follows one rule. The admin changes what changes often, in the app: group membership, the service accounts, the destinations, the pages, and the instance's name. The operator sets who holds power and where the service reads from, in the environment file: the rights, sign-in, the service's own Google credential, and the file locations.

A change in the app applies at once. The service reads the environment file only when it starts, so a changed variable applies after the operator recreates the container.

Give a person a right

Two rights sit above ordinary use, and a person who builds dashboards needs neither. The admin right manages the instance. The analyst right curates the theme library, the instance fonts and the datasource library, sets the Official stamp, and sends a delivery with Send now. It also reads a private sheet or file with the service's own Google account.

Neither right reaches the warehouse. Google Cloud decides who may run a query under a service account (Register service accounts).

In the app

The Access area shows who holds each right. It does not edit them. A group entry in an allowlist moves the everyday change into the app: every member of the group holds the right.

  1. Open Administration, then Access.
  2. Under Rights, find a group entry in the allowlist, such as group:analysts.
  3. In Groups, add the person to that group, or remove the person.

The right follows the membership at once. A group that an allowlist names carries a grants admin or grants analyst tag on its row.

In the environment file

To give one person a right without a group, ask the operator to add the address. An address in an allowlist applies after the operator recreates the container.

With nothing configured

An unset allowlist means nobody holds the right. Rights reads nobody for analysts. An instance with no admin shows no Administration to anyone.

Read a setting you cannot change here

The operator sets some settings in the environment file. Each one shows in the area whose job it serves, with the variable that sets it and its value on this instance. Sign-in settings are in Access. The warehouse and the outbound hosts are in Credentials. The rest are in Configuration.

A row reads not set when the deployment gives the variable no value. A row for a secret reads set or not set and never shows the value. To change any of them, ask the operator to edit the environment file and recreate the container.

The How people sign in section of the Access area. Each line names one environment variable and its value on this instance, such as ARKUSH_IDENTITY: proxy and ARKUSH_SIGNIN_ALLOW: not set. A line under the list says that a change applies after the container is recreated.
The sign-in settings in the Access area. Each row names the variable and its value.

Two kinds of setting have no row. A file location has none: the area that uses the file names its path where you meet it. A setting with its own control in Administration, such as the two rights, the groups backend or the upload quota, shows in that control instead.

Limit agents, downloads and open sharing

The access settings decide what people on this instance may do: connect an agent, take rows away, and open a dashboard to everyone signed in. Each one starts at the widest value. An admin changes them in the app. No environment variable sets them, and they apply with no restart.

The agent setting and the rows setting can take a list of named people and groups. An entry is an email address or a group, written group:<name>. To manage those groups, see Manage groups.

In the app

  1. Open Administration, then Access, and find Settings.
  2. In Connect an agent, choose who may connect one. An agent acts as the person who approved it, and reads nothing that person cannot read.
  3. In Take rows away, choose who may take rows off the instance. This covers the CSV download, the export of an open dashboard, the tables in a subscription, and how many rows an agent's SQL preview answers with.
  4. In Open a dashboard to everyone signed in, choose Every editor or Admins only. This covers dashboards, datasource-library entries and uploaded files. Where the instance publishes to the internet, the same choice decides who may publish: Every editor lets each owner publish their own dashboard, and Admins only keeps publishing to admins who own the dashboard. Admins only also keeps Transfer ownership to admins, so an owner cannot hand a dashboard to another person.
  5. If you chose Named people and groups, add each entry.
  6. Select Save.
Limit who may connect an agent to one group. Enter adds the entry, and Save applies it.

The settings apply to the next request. A person the agent setting refuses loses their agents at the next call, and their connection stops with a message naming an admin. A person the rows setting refuses stops seeing Data as CSV, and their export of a dashboard writes the structure with no rows in it. Every change writes one audit line.

What the rows setting does not do

A viewer's browser holds every row of every snapshot, because the dashboard draws and filters from those rows. The rows setting hides the acts that write a file. It cannot keep the rows out of the browser, and a table block still shows them. The two controls that do hold are who may view a dashboard, and what the dashboard's SQL selects: a dashboard built on totals hands out totals.

With nothing set

Everyone signed in may connect an agent, every viewer may take rows away, and every editor may open a dashboard to everyone signed in.

If anyone can sign in to this instance, only an admin shares a dashboard, opens it to everyone signed in, or transfers its ownership, whatever the sharing setting says. Everyone else keeps their dashboards private, so no person meets a stranger's email address.

Publishing to the internet is off until the operator sets ARKUSH_ALLOW_PUBLISHING=true in the instance's environment. The Access area reports the switch. With it off, nobody publishes, the Share panel shows no publish section, and every published address answers nothing — including one published before the switch went off. With it on, the sharing choice above decides who may publish, and only a dashboard's owner publishes it. Any editor can unpublish, whatever the switch and the setting say.

To take down a published dashboard that you cannot edit, select it with Select on the Dashboards page and close it to private. That deletes the published copy. Access lists every published dashboard. Moving a published dashboard to the trash unpublishes it too, and restoring it does not publish it again.

Manage groups

A group is a named set of people. A person can share a dashboard with a group, and an allowlist can name one. The instance reads membership from one of two backends. The section heading names which: Groups for the membership file that admins edit, and Google Groups for the Google Workspace directory.

In the app: Groups

  1. Open Administration, then Access, and find Groups.
  2. Select Add group….
  3. Type a short name in lowercase, such as finance. A name holds no space, : or @.
  4. Type or paste addresses into Add members, then press Enter.
  5. Select Add group.
Add a group: type its name, paste the addresses, press Enter, then select Add group.

To change a group, select Edit on its row. Remove a member with the close button on the member's chip, add members the same way, and select Save members. The editor marks a member that the instance has never seen — no sign-in, no dashboard, no share, no other group. The mark asks for a typo check and does not stop the save.

Delete removes a group after a dialog that counts the dashboards shared with it. Shares and allowlist entries that name the group then match nobody.

In the app: Google Groups

  1. Open Administration, then Access, and find Google Groups.
  2. Select Add group….
  3. Type the group's address, such as [email protected].
  4. Select Add group. The service checks the address against the directory first.

Membership shows read-only. Change who is in a group in Google. After Remove, this instance no longer reads the group, and the group stays in Google.

In the environment file

The google backend also needs a grant outside the file. The service's own identity needs the Groups Reader admin role, in the Google Workspace Admin console.

With nothing configured

Groups work with no setting. A new instance shows an empty Groups section, and the first group an admin adds creates the file. On the Google backend, a group that Google has not answered for yet lists no members.

Register service accounts

A BigQuery datasource that runs on the server names a registered service account in Runs as. The service impersonates that account, so no key is stored anywhere. Three parties share this task. The admin keeps the registry. The operator gives the service its credential. IAM in Google Cloud decides who may use each account.

In the app

  1. Open Administration, then Credentials.
  2. Select Register account….
  3. Type the account's address, such as [email protected].
  4. In Label, say what the account is for.
  5. Select Register account.
  6. Select Verify on the new row.
Register an account, then verify it. On a server with no server-side BigQuery, Verify names the missing variable.

Verify asks Google for a real token. On failure, the row names the cause. If a gcloud command fixes that cause, the row shows the command.

Remove takes an account out of the registry after a dialog. Datasources that name the account keep their data, but their next run refuses and their schedules pause.

Datasources without an account

This section appears only while a BigQuery datasource names no service account. Such a datasource cannot run on the server, and its schedule is paused. Each row opens the dashboard's or the library entry's details page.

The fix is Runs as: in the dashboard's Data workspace, or on the entry's details page. A person who can edit the dashboard, or manage the entry, sets it. The section disappears when the list is empty.

In the environment file

In Google Cloud

Google Cloud decides who may use an account, never arkush. Whoever manages IAM on the account's project makes these grants:

With nothing configured

Every instance has the registry. Empty, the section reads "No service accounts registered yet.", and nothing runs as a service account. With no ARKUSH_BQ_PROJECT, the Server-side BigQuery row in Configuration reads not configured — people query with their own Google accounts. Verify then names the variable.

See what leaves on a schedule

A delivery posts a dashboard's charts and tables to a Slack channel on a schedule. Each one is set up on its own dashboard, so no single dashboard shows the whole picture. The Deliveries area does: every delivery on the instance, grouped by the destination it posts to.

In the app

  1. Open Administration, then Deliveries.
  2. Read What leaves on a schedule. Each destination lists the dashboards that send to it, with the schedule, who blessed it, and how the last send went.
  3. To see a delivery's message and blocks, select the dashboard's name.

A delivery marked not blessed — never sends is set up but inactive. A delivery sends only after an analyst selects Send now on that dashboard and the send succeeds. An analyst who loses the analyst right, or loses edit access to the dashboard, stops every delivery they blessed. A delivery also stops when a datasource's rows no longer match the run that produced them, because someone wrote rows into the dashboard after the run. One authorized run of each affected datasource starts the delivery again.

Before you remove a destination

Each destination in the registry below lists the dashboards it serves. Removing the entry stops every one of them at the next schedule, and the dashboards themselves say nothing about it. Read that line first.

With nothing set

No dashboard sends anything, and the list says so.

Add delivery destinations

A destination is a named Slack channel that deliveries post to. A dashboard names the destination and never sees its bot token. The Destinations section is the one place that shows the tokens.

Before you start

  1. Get the bot token of the Slack app installed in the workspace. It needs the chat:write and files:write scopes. With files:read too, a delivered table posts in the thread of the message that carries its charts.
  2. Invite the bot to each channel it posts to.
  3. Copy each channel's id, such as C0123456789. The channel name does not work.

In the app

  1. Open Administration, then Deliveries.
  2. Write one entry per channel in the editor, in this shape:
    destinations:
      team-metrics:
        kind: slack
        channel: C0123456789
        token: xoxb-…
        label: '#team-metrics'
  3. Select Save destinations.
One Slack destination written into the editor, then saved. Use your bot's real token.

The service checks the file before it writes. An invalid file refuses with the problem named, and the stored file stays as it was. If the file changed after it loaded, the save refuses too: select Reload and make the edit again.

Subscriptions send a dashboard to a person's own Slack direct messages. For them, the bot also needs the users:read.email and im:write scopes. Where the file holds more than one Slack entry, mark that bot's entry with dm: true.

In the environment file

With nothing configured

Every instance has the registry. Empty, the editor is blank, and the Deliveries section offers no Deliver…. An admin reads that channels are added here. Everyone else reads that the server has no channel to post to. Without a bot marked for direct messages, the Subscriptions panel does the same: an admin reads the setup step, and everyone else reads that the server cannot send direct messages.

See who joined the waitlist

On an instance that keeps a waitlist, a feature the instance does not set up says it comes with an org install and offers Join the waitlist. Three features take the offer: Slack subscriptions, channel deliveries, and server-side BigQuery. One press stores the person's email address, the feature and the date.

In the app

  1. Open Administration, then Deliveries.
  2. Read Waitlist. Each feature lists the people who joined, with the date.

A person leaves the list from the same panel where they joined. Delete profile removes their entries too.

In the environment file

With nothing set

No surface offers the waitlist, and each one keeps the line it shows where a feature is not set up. The section shows here only when the list holds entries from a time it was on.

Set the instance identity

The instance identity is what the instance says about itself: a name, a logo, and a security contact. The name shows in the toolbar and the browser tab, and the logo in the toolbar, to everyone who opens the app. The landing page, the legal pages and the About page use the name too.

In the app

  1. Open Administration, then Appearance, and find Instance identity.
  2. In Name, type the instance's name.
  3. In Logo, type the https address of an image.
  4. In Security contact, type an email address or an https page, such as [email protected].
  5. Select Save.
Set the name, the logo and the security contact, then select Save.

With a logo, the toolbar shows the logo and uses the name as its alternative text. The service publishes the security contact at /.well-known/security.txt, where a security researcher looks for it. Every published dashboard's page also carries Report this page, which sends its reader to the same contact. With no contact set, a published page has no report link.

In the environment file

Nothing. No variable sets the identity. The old variables ARKUSH_INSTANCE_NAME, ARKUSH_LOGO_URL and ARKUSH_SECURITY_CONTACT stop the service at start, with a message naming Appearance, where the identity is set.

With nothing set

The toolbar says "arkush" alone, and the instance publishes no security.txt.

Choose the default theme

Every new dashboard starts with the default theme, in the app and from an agent. A theme with a light face and a dark face shows each viewer the face for their mode. Dashboards that exist keep their own theme.

In the app

  1. Open Administration, then Appearance, and find Default theme.
  2. In Theme for new dashboards, pick a theme.

The pick saves at once. The list offers the house theme, the built-in themes, and the saved themes of the theme library. An analyst saves a theme to the library from the theme editor.

A server can hold a different theme for each mode from an earlier version. The list then reads Per mode with the two themes, and new dashboards take the theme for their creator's mode. A dashboard that an agent creates takes the light one. Pick one theme to replace both.

In the environment file

Nothing. No variable sets the default theme.

With nothing set

New dashboards take the house theme, Arkush, in a light face and a dark face. A pick saved as Arkush Light or Arkush Dark in an earlier version means Arkush too, and a pick of one face of a built-in theme means that whole theme. Pick Classic for the plain look the app draws without a theme. A pick whose saved theme was deleted reads Missing theme — house theme applies.

Write the instance pages

The instance pages carry the instance's own words: the landing copy, the examples page, the privacy policy, and the terms of service. Each page is one markdown file. A privacy policy names who holds the data on this instance, so the software ships the editor and no words.

In the app

  1. Open Administration, then Pages.
  2. In Page, pick Landing page, Examples, Privacy policy or Terms of service. Examples shows only on an instance that publishes dashboards to the internet.
  3. Write the page in markdown.
  4. Select the save button, such as Save privacy policy.
  5. Open the page in a new tab and read the result.
Pick a page, write it in markdown, then select the save button that names the page.

The landing copy replaces the headline and the paragraph under it, between the instance name and the sign-in buttons. The buttons and the agent setup stay. A paragraph that holds only ![description](link) shows a picture, or a YouTube or Vimeo video.

The service publishes the privacy policy at /privacy and the terms at /terms. The landing page links each one that has words. The pages take headings, paragraphs, lists, links, bold, italics and code. Raw HTML shows as plain text.

The examples page shows visitors the dashboards you chose, at /examples. The landing page links it from the top bar and beside the sign-in buttons. To add a dashboard, publish it first, then link its published address and say in one line what it shows. A paragraph that holds only ![description](link) shows a picture, such as a preview of the dashboard. The examples page plays no video.

If the file changed after it loaded, the save refuses: select Reload and make the edit again.

In the environment file

With nothing written

A blank landing page shows the stock copy. A blank examples page, privacy policy or terms do not exist: the address answers not found, and nothing links to it. If the service cannot read or write a file, the section shows the error with the file's path and its variable. The operator fixes the path.

Review the people on the instance

The Users area lists everyone the instance has seen: from sign-ins, dashboards, shares, agents and groups. It stores nothing of its own. Each row counts the person's agents, dashboards, shared datasources and uploaded storage, and shows their rights and groups.

In the app

  1. Open Administration, then Users.
  2. Search by email or by log pseudonym, or sort by dashboards owned, storage used or agents connected.
  3. Select a person's email to open the row.
Search for a person, then select the email to open the row.

The open row lists the person's onboarding answers, dashboards, shares, shared datasources, uploaded files, subscriptions and connected agents. Remove on a subscription stops its sends after a dialog. When a person leaves, the row is where Offboard a person starts.

Find a person in the logs

The service's logs never hold an email address. Each line names a person by a pseudonym, for example u_4cd3a619b5290108, which stays the same for that person on this instance. The open row of a person shows their pseudonym. To find who a pseudonym in a log line belongs to, type it in the search field.

When someone reports an error, ask for the time and the code. The link beside the message opens its entry, and the entry shows the code. Give the operator the code, the time and the person's pseudonym. The operator finds the lines with the steps in the install guide, in the section on reading the logs.

In the environment file

With nothing configured

The Users area needs no setting. A new instance lists nobody until someone signs in. An unset quota reads no limit.

Transfer a dashboard or recover access

An admin sees every dashboard's title, owner and dates. To open a dashboard, the admin still needs a share. The acts below reach any dashboard. Each act shows in the dashboard's own sharing list or version history, where the owner sees it.

In the app: one dashboard

  1. Open Administration, then Users, and open the owner's row.
  2. Under Dashboards they own, open the dashboard's actions menu.
  3. Select Grant me edit access… or Transfer ownership….
  4. For a transfer, type the new owner's email and select Transfer ownership.
  5. Read the dialog and confirm.
Transfer one dashboard from its owner's row. The dialog says what changes before it acts.

In the app: several dashboards

  1. Open Dashboards — the instance's dashboard list, in the section links at the top, outside Administration.
  2. In Scope, pick Every dashboard on this instance.
  3. Select Select and tick the dashboards.
  4. In the bar, select Share…, Remove access…, Who can view, or More and then Transfer ownership….
  5. Read the dialog and confirm.

In this scope, the Access filter on the dashboard list — not the Access area of Administration — offers No owner recorded. It finds the dashboards that nobody owns, which only an admin can reach. Transfer each one to a new owner.

In the environment file

Nothing. These acts work on every instance.

Revoke agent grants

A grant lets an AI agent act as the person who approved it. The agent reaches the dashboards that person reaches, and each change it makes carries that person's name. A person disconnects their own agents in the Connect-an-agent panel. An admin sees and revokes every grant.

In the app

  1. Open Administration, then Users. The Agents column counts each person's grants.
  2. Open the person's row.
  3. Under Connected agents, select Revoke on one agent, or Revoke all.
  4. Read the dialog and confirm.
Part of a person's open row in the Users area. Shared with them lists one dashboard the person can view, with Remove all 1 share… at the right. Connected agents reads that no agents are connected and that Revoke all still signs out every browser signed in as this account. The Revoke all button is at the right.
Connected agents in a person's row. Revoke all shows even when no agent is connected.

A revoked agent stops at once, and a new connection needs a fresh approval. When the service signs people in itself, Revoke all also signs out every browser signed in as the person. It deletes the person's passkeys, and every unused sign-in code sent to the person stops working. Revoke all also removes the person's subscriptions and inbox, and takes the person off every access setting that names them. It does not stop a new sign-in: to end the access of a person who leaves, see Offboard a person. Connected agents shows for every person, including a person who connected no agent. For that person, Revoke all still ends their browser sessions.

In the environment file

No variable turns agents on or off. To limit who may connect one, use the agent setting in Access. When the service signs people in itself, ARKUSH_SIGNIN_ALLOW binds agents too: an address taken off the list stops its agents. A * or @example.org entry does not name a person, so no single address comes off it. There, and behind an identity-aware proxy, Revoke all is the cut-off.

Read the onboarding answers

The onboarding ask puts a few of the instance's own questions to each person once, at their first sign-in. The answers tell an admin how to set the person up: which group to add them to, which data to share. Only the person and the admins read the answers.

In the app

  1. Open Administration, then Users.
  2. Open a person's row.
  3. Read the answers under About.

To see how many questions this instance asks, open Administration, then Pages: the Onboarding ask row counts them.

Delete profile removes the person's answers, subscriptions and inbox after a dialog, and the ask returns at their next visit. It also unpublishes every published dashboard the person owns, and the dialog names how many. A person edits or clears their own answers from About you in the account menu. The menu shows About you while the instance asks at least one question, or while the person keeps at least one answer.

In the environment file

The app has no editor for the questions. The operator writes them in ask.yml in the state directory, or in the file that ARKUSH_ASK_FILE names. The file holds at most 10 questions, each a label and an optional hint. An edit applies without a restart, so a new question is one request to the operator.

With nothing configured

With no file, or with a file that holds no questions, the Onboarding ask: row reads none. The ask reaches nobody, and stored answers stay readable. The Users area still lists every sign-in.

Offboard a person

An account is its email address, so ownership, shares and rights follow the address. When a person leaves, the operator, the admin, and the owners of the person's accounts outside arkush each end one part.

End every way in before Revoke all. The service asks a sign-in provider only at sign-in. So a person whose provider account or mailbox works after Revoke all signs in again and can add a new passkey.

  1. Operator: where ARKUSH_SIGNIN_ALLOW names the address, remove the address from the list. Behind an identity-aware proxy, block the address at the proxy.
  2. Identity provider: suspend the person's account in the organization's identity provider and mail system, such as Google Workspace.
  3. GitHub: where people sign in with GitHub, remove the person from each organization in ARKUSH_SIGNIN_GITHUB_ORGS.
  4. Admin: in Administration → Users, open the person's row and select Revoke all under Connected agents. Revoke all ends the person's sessions, agent grants, passkeys, unused sign-in codes and subscriptions.
  5. Operator: remove the address from ARKUSH_ADMINS and ARKUSH_ANALYSTS where it is named.
  6. Admin: under Dashboards they own, select Transfer all N to… and type the new owner.
  7. Admin: under Shared with them, select Remove all N shares….
  8. Admin: under Sandboxes, select Remove all sandboxes. The section shows only when the person built charts over dashboards they could view. The sandboxes stay until you remove them, so the dashboards' editors can still add a chart from them.
  9. Admin: in Administration → Access, select Edit on each group the person is in and remove their chip, then Save members. On the Google backend the section reads Google Groups and membership changes in Google, not here.
  10. Google Cloud: remove the person's Service Account User role on each service account. Where a Google group holds the role, take the person out of that group instead.

Transfer all N to… shows only for a person who owns more than one dashboard. With one dashboard, use Transfer ownership… on its row. Google-backed group membership changes in Google.

A published dashboard keeps its published address when it is transferred, so the links people posted keep working. The notice after Transfer all N to… names how many of the transferred dashboards are published. Delete profile unpublishes every published dashboard the person still owns, and those addresses stop answering. To keep an address, transfer the dashboard before you delete the profile.

Two steps stop a schedule that rests on the person's run, and the first one you reach is the one that acts. Removing the address from ARKUSH_SIGNIN_ALLOW pauses every datasource the person blessed. That pause starts at the first sweep after the operator restarts the service with the new list, whatever Google still grants the account. The Google Cloud step pauses the warehouse datasources among them, within an hour.

A Slack delivery that the person blessed with Send now stops at its next due send. It stops when the person loses the analyst right or edit access to the dashboard, or leaves the sign-in allowlist. Another analyst's Send now starts it again.

WARNING — Finish every step before the organization gives the address to someone new. A reused address inherits what the old account still holds: its dashboards, its shares, its group memberships and its rights.