> ## Documentation Index
> Fetch the complete documentation index at: https://docs.jun.so/llms.txt
> Use this file to discover all available pages before exploring further.

# Secrets and settings

> Every Worker secret, variable and binding Jun reads, what it does, and how to set it.

Jun needs one secret to run: `SETUP_TOKEN`. Everything else is optional and turns on a provider or integration. Bindings (database, storage, queue, AI) are created for you by the Deploy button or `npm run deploy`.

## Worker secrets and variables

| Name | Required | What it does |
| - | - | - |
| [`SETUP_TOKEN`](#setup_token) | Yes | Creates the owner account; recovers access |
| [`OPENAI_API_KEY`](#openai_api_key) | No | Lets the AI use OpenAI |
| [`OPENAI_BASE_URL`](#openai_base_url) | No | Sends OpenAI requests through another endpoint, such as Cloudflare AI Gateway |
| [`JUN_SECRET_<NAME>`](#jun_secret_name) | No | A key for actions, used as `{secrets.NAME}` |
| [`GITHUB_TOKEN`](#github_token) | No | Files issues on GitHub |
| [`GITHUB_API_URL`](#github_api_url) | No | GitHub Enterprise Server's API address |
| [`LINEAR_API_KEY`](#linear_api_key) | No | Files issues on Linear |
| [`LINEAR_API_URL`](#linear_api_url) | No | Another Linear GraphQL endpoint |

### SETUP\_TOKEN

Any passphrase of at least 16 characters. You type it once, on your first visit, to create the owner account and workspace. After that it's used only on `/recover`, which lets the owner register a new passkey after losing every one.

The Deploy button asks for it. Without it (or with a shorter one), setup fails with `SETUP_TOKEN isn't configured (needs 16+ characters). Set it as a Worker secret.` Keep it somewhere safe: anyone with it can add a passkey to the owner's account. Changing it later is safe; only `/recover` uses it.

### OPENAI\_API\_KEY

An OpenAI API key, used when **Settings → AI** has OpenAI as the provider. If the provider is OpenAI and the key is missing, every AI reply hands off to your team instead, and the brief says `OPENAI_API_KEY isn't set. Add it as a Worker secret.` See [Models](/ai/models).

### OPENAI\_BASE\_URL

Optional. Sends OpenAI requests to this base URL instead of OpenAI's, for example a [Cloudflare AI Gateway](https://developers.cloudflare.com/ai-gateway/) endpoint for logging, caching and rate limits.

### JUN\_SECRET\_\<NAME>

A key for your actions. An action file writes `{secrets.ACME_API_KEY}` in a header, and the desk fills it from `JUN_SECRET_ACME_API_KEY`:

```yaml actions/lookup_order.yaml theme={null}
headers:
  Authorization: Bearer {secrets.ACME_API_KEY}   # Worker secret JUN_SECRET_ACME_API_KEY
```

`NAME` is `UPPER_SNAKE_CASE`. Instead of a Worker secret, an admin can paste the key on the action's page on the desk. When both exist, the Worker secret wins. See [Actions](/ai/actions).

### GITHUB\_TOKEN

A GitHub token for **Create issue**: a [fine-grained personal access token](https://github.com/settings/personal-access-tokens/new) for the one repository, with **Issues: Read and write**. Instead of the secret, an admin can paste it in **Settings → Issue trackers**; the secret wins. See [Issues](/inbox/issues).

### GITHUB\_API\_URL

Optional. The API address for GitHub Enterprise Server. Default `https://api.github.com`.

### LINEAR\_API\_KEY

A Linear personal API key (Linear → **Settings → Security & access**). Instead of the secret, an admin can paste it in **Settings → Issue trackers**; the secret wins.

### LINEAR\_API\_URL

Optional. Another Linear GraphQL endpoint. Default `https://api.linear.app/graphql`.

## Set a secret

<Tabs>
  <Tab title="Cloudflare dashboard">
    <Steps>
      <Step title="Open your Worker">
        In the [Cloudflare dashboard](https://dash.cloudflare.com), go to **Workers & Pages** and select your desk's Worker (`jun-desk` unless you renamed it).
      </Step>

      <Step title="Add the secret">
        Open **Settings → Variables and Secrets**, press **Add**, choose type **Secret**, enter the name (for example `OPENAI_API_KEY`) and the value.
      </Step>

      <Step title="Deploy">
        Press **Deploy**. The Worker picks it up at once.
      </Step>
    </Steps>
  </Tab>

  <Tab title="Wrangler">
    From your checkout of the repository, logged in with `npx wrangler login`:

    ```sh theme={null}
    npx wrangler secret put OPENAI_API_KEY
    ```

    Wrangler asks for the value and deploys it. To remove one:

    ```sh theme={null}
    npx wrangler secret delete OPENAI_API_KEY
    ```

    List the names (never the values) with `npx wrangler secret list`.
  </Tab>
</Tabs>

<Tip>
  Set the URL settings (`OPENAI_BASE_URL`, `GITHUB_API_URL`, `LINEAR_API_URL`) as type **Secret** too. `wrangler deploy` keeps secrets, but replaces plain-text variables with the ones in `wrangler.jsonc`, which has none, so a plain-text variable added on the dashboard disappears on your next `npm run deploy`.
</Tip>

Secrets survive upgrades: `npm run deploy` never touches them.

## Keys that aren't Worker secrets

Some keys are created or pasted on the desk and kept by the desk itself:

| What | Where it's set | Where it's kept |
| - | - | - |
| Action keys pasted on an action's page | **Agent → Actions**, on the action's page | The workspace's Durable Object storage. Never in the database, never returned, only the last 4 characters shown |
| GitHub token, Linear key pasted in Settings | **Settings → Issue trackers** | Same as above |
| Web Push (VAPID) key pair | Created on first use | The workspace's Durable Object storage; only the public key is ever returned |
| Identity secret | **Chat widget → Behaviour → Identify signed-in customers** | The D1 database (the desk needs it to check tokens). Admins can see and rotate it |
| ChatGPT sign-in | **Settings → AI** | The D1 database |
| API tokens for the CLI | **MCP → API tokens** | The D1 database, as SHA-256 hashes only |

## Bindings

`wrangler.jsonc` declares these. The Deploy button and `wrangler deploy` create the resources; you don't set IDs.

| Binding | Type | Default name | Used for |
| - | - | - | - |
| `DB` | D1 database | `jun-desk` | Everything durable: conversations, contacts, knowledge text, settings, agent config versions |
| `FILES` | R2 bucket | `jun-desk-files` | Attachments, logos, screenshots, knowledge files |
| `AI` | Workers AI | | The default chat model, embeddings and reranking |
| `CRAWL_QUEUE` | Queue (producer and consumer) | `jun-desk-crawl` | Website crawling, one message per page |
| `CONVERSATION` | Durable Object | | One per conversation: live sockets and AI turns |
| `WORKSPACE_HUB` | Durable Object | | One per workspace: inbox events, presence, live visitors, stored keys |
| `KNOWLEDGE_INDEX` | Durable Object | | One per workspace: vector search over your knowledge |
| `ASSETS` | Static assets | | The dashboard, widget frame and loader |

One cron trigger runs every 15 minutes (topic labels for quiet chats); its 03:15 UTC run also re-syncs knowledge.

<Warning>
  Two desks in one Cloudflare account must use different database, bucket and queue names. With the default names, a second Worker binds to the first desk's `jun-desk` database, `jun-desk-files` bucket and `jun-desk-crawl` queue and shares its data. Change the names on the Deploy button's form (for example `jun-trial`, `jun-trial-files`, `jun-trial-crawl`).
</Warning>

## Local development

| File or variable | What |
| - | - |
| `.dev.vars` | Worker secrets for `npm run dev`. Copy `.dev.vars.example` and set `SETUP_TOKEN`; add any secret from the table above the same way (`OPENAI_API_KEY=…`) |
| `.env` with `CLOUDFLARE_ACCOUNT_ID` | Workers AI always calls Cloudflare, even locally. Set this when your Wrangler login has several accounts |
| `JUN_STATE_DIR` | A separate local database and storage folder, for example `.wrangler/e2e-state` for the end-to-end tests |

Both files are gitignored. See [Local development](/deploy/local-development).

<CardGroup cols={2}>
  <Card title="Security" icon="shield" href="/reference/security">
    How the desk protects accounts, keys and customer data.
  </Card>

  <Card title="Deploy to Cloudflare" icon="cloud" href="/deploy/cloudflare">
    The Deploy button and the command line.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.