> ## Documentation Index
> Fetch the complete documentation index at: https://meridiona-mintlify-3ba0cdfa.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Connect Meridian to Jira Cloud for Automatic Tracking

> Link your Jira Cloud workspace to Meridian with a one-command browser login (OAuth + PKCE), or fall back to a static API token. Sessions are classified against your open tickets and time is tracked without manual input.

Meridian fetches your open Jira tickets, stores them locally as `pm_tasks`, and uses them during session classification. Every time you close a coding or research session, Meridian's classifier checks which ticket that work most likely belongs to and writes a `ticket_links` row to its database — no timesheets, no manual updates required.

Meridian supports two ways to authenticate to Jira Cloud:

* **Browser OAuth (recommended)** — one command, no API token, your site is discovered automatically, and access tokens auto-refresh.
* **Static API token (fallback)** — three environment variables. Use this when your Atlassian org blocks third-party OAuth apps or you need a fully scripted, headless setup.

If both are configured, OAuth wins.

## Prerequisites

* A Jira Cloud account (Jira Data Center is not supported)
* Meridian installed and the daemon running (`meridian status` to confirm)
* For OAuth: a desktop browser on the machine running Meridian

## Connect with browser OAuth (recommended)

The installer offers OAuth inline during `meridian setup` / `./install.sh`. You can also run the login at any time after install:

```bash theme={null}
meridian oauth-login jira
```

The command:

1. Generates a PKCE verifier and opens your default browser to Atlassian's consent screen.
2. Waits for you to click **Accept**. Atlassian redirects back to a short-lived loopback server at `http://127.0.0.1:9123/callback`.
3. Exchanges the authorization code for an access token and a refresh token.
4. Writes them to `~/.meridian/oauth/jira.json` (mode `0600`, owner-only readable).

After the browser shows "Login successful, you can close this tab", restart the daemon so it picks up the new credentials:

```bash theme={null}
meridian restart
```

That's it — your site is discovered automatically from the account you sign in with. There is nothing to add to `~/.meridian/.env`.

### Scopes requested

The Atlassian consent screen lists the four scopes Meridian asks for:

| Scope             | Why Meridian needs it                                                                                                              |
| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `read:jira-work`  | Read open issues you're assigned to.                                                                                               |
| `write:jira-work` | Post worklogs to issues you classify against (only after you approve a draft in the dashboard).                                    |
| `read:jira-user`  | Used by `meridian doctor`'s `/myself` health probe to confirm the token works.                                                     |
| `offline_access`  | Issues a refresh token so the daemon can mint new access tokens in the background — without this, you'd be re-prompted every hour. |

Meridian never creates, modifies, closes, or deletes tickets on its own. The only write call is a draft worklog you have explicitly approved in the dashboard.

### The token store

Tokens live at `~/.meridian/oauth/jira.json`:

```text theme={null}
~/.meridian/oauth/jira.json   # mode 0600, owner read/write only
```

The file is created with restrictive permissions up front. The daemon refreshes the access token before each request when it's near expiry and persists the rotated refresh token back to the same file — Atlassian rotates refresh tokens on every refresh, so the store must be writable by the daemon.

To revoke access, either delete the token store and run `meridian restart`, or revoke the grant from your Atlassian account's connected apps page. The next daemon start will fall back to static API-token auth if it is configured, otherwise it will report `jira: not configured`.

### Override the OAuth client ID

Meridian ships with a public Atlassian client ID baked in — PKCE has no client secret, so there is nothing to protect. If your organisation runs its own Atlassian app (for example, to scope OAuth to an internal site allowlist), override the baked-in value:

```bash theme={null}
# ~/.meridian/.env
JIRA_OAUTH_CLIENT_ID=your-atlassian-app-client-id
```

Then re-run `meridian oauth-login jira`.

## Connect with a static API token (fallback)

Use this path if `meridian oauth-login jira` fails with an org-approval error ("site admin must authorize this app" or user app installs disabled), or when running Meridian in a headless environment where you cannot open a browser.

<Steps>
  <Step title="Create a Jira API token">
    Navigate to [id.atlassian.com/manage-profile/security/api-tokens](https://id.atlassian.com/manage-profile/security/api-tokens), click **Create API token**, give it a descriptive label such as `meridian-local`, and copy the value. Atlassian only shows the token once.
  </Step>

  <Step title="Add the credentials to ~/.meridian/.env">
    Run `meridian config edit` and add the Jira block:

    ```bash theme={null}
    # ~/.meridian/.env

    JIRA_BASE_URL=https://your-org.atlassian.net
    JIRA_EMAIL=you@your-org.com
    JIRA_API_TOKEN=your-api-token-here

    # Optional: restrict sync to specific project keys (comma-separated)
    # JIRA_PROJECT_KEYS=KAN,ENG
    ```
  </Step>

  <Step title="Restart the daemon">
    ```bash theme={null}
    meridian restart
    ```
  </Step>
</Steps>

All three variables must be present for the basic-auth path to activate. Static-token requests go directly to your `JIRA_BASE_URL`; OAuth requests instead go through `https://api.atlassian.com/ex/jira/{cloudId}` with a Bearer token. Both paths share the same request layer, so the rest of Meridian — classification, doctor, worklog drafts — works identically.

## How Meridian picks an auth path

On every Jira request, the daemon resolves credentials in this order:

1. If `~/.meridian/oauth/jira.json` exists, use OAuth. Refresh the access token first if it's near expiry.
2. Otherwise, if `JIRA_BASE_URL`, `JIRA_EMAIL`, and `JIRA_API_TOKEN` are all set, use basic auth.
3. Otherwise, report `jira: not configured` and skip Jira sync.

This means an OAuth-connected installation can also keep static creds in `.env` as a documented fallback — they will simply be ignored as long as the token store exists.

## Verify the connection

<Steps>
  <Step title="Run a health check">
    ```bash theme={null}
    meridian doctor
    ```

    Look for `jira: connected` in the output. The check calls Jira's `/myself` endpoint, which works under both OAuth (via the `read:jira-user` scope) and basic auth.
  </Step>

  <Step title="Inspect the task cache (optional)">
    ```bash theme={null}
    sqlite3 ~/.meridian/meridian.db \
      "SELECT task_key, title, status FROM pm_tasks LIMIT 10;"
    ```

    You should see rows for your open issues.
  </Step>
</Steps>

## Limit which projects are synced

By default Meridian fetches every open ticket assigned to you. To restrict it to one or more projects, set `JIRA_PROJECT_KEYS` to a comma-separated list of project keys:

```bash theme={null}
JIRA_PROJECT_KEYS=KAN,ENG
```

`JIRA_PROJECT_KEYS` applies to both auth paths.

## Force-refresh the Jira task cache

The daemon refreshes `pm_tasks` automatically at startup and on its background poll cycle. To pull the latest data on demand without restarting, run:

```bash theme={null}
meridian tasks-sync
```

This bypasses the 5-minute staleness gate and re-syncs every configured tracker (Jira, GitHub, Linear) in one shot.

## Troubleshooting

<AccordionGroup>
  <Accordion title="meridian oauth-login jira fails with an org-approval error">
    Some Atlassian organisations require a site admin to authorize third-party OAuth apps before any user can grant consent. If you see "site admin must authorize this app" or "user app installs are disabled", switch to the [static API token path](#connect-with-a-static-api-token-fallback) — basic auth works without org-level approval.
  </Accordion>

  <Accordion title="login() fails with 'no refresh token returned'">
    Atlassian only issues a refresh token when the `offline_access` scope is granted. If the consent screen omits it, the daemon refuses the response so you don't end up with a token that silently expires after an hour. Re-run `meridian oauth-login jira` and make sure all four scopes are listed on the consent screen.
  </Accordion>

  <Accordion title="401 Unauthorized after basic-auth setup">
    Double-check that:

    * `JIRA_EMAIL` matches the email address on your Atlassian account exactly.
    * `JIRA_API_TOKEN` is the token value itself, not a label or partial string.
    * `JIRA_BASE_URL` ends with `.atlassian.net` and has no trailing slash.

    Regenerate the API token in Atlassian account settings if you're unsure.
  </Accordion>

  <Accordion title="pm_tasks table is empty after connecting">
    An empty `pm_tasks` table means the JQL query returned no issues. Check that:

    * Your account has at least one open issue assigned to it in the targeted projects.
    * If you set `JIRA_PROJECT_KEYS`, confirm the keys are correct (they are case-sensitive, e.g. `KAN` not `kan`).

    Run `meridian tasks-sync` to force a re-sync after fixing the configuration.
  </Accordion>

  <Accordion title="meridian doctor reports jira: not configured">
    Jira is considered configured when either:

    * The OAuth token store exists at `~/.meridian/oauth/jira.json`, OR
    * All three of `JIRA_BASE_URL`, `JIRA_EMAIL`, and `JIRA_API_TOKEN` are set in `~/.meridian/.env`.

    Run `ls -l ~/.meridian/oauth/jira.json` to check for the token store, or `meridian config edit` to confirm the static creds.
  </Accordion>
</AccordionGroup>
