Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions guides/dashboard.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,41 @@ Navigate to `/sessions` to see every completed session for the current day, orde

Navigate to `/apps` to see all-time usage statistics aggregated by application: total time, session count, average session length, and the last time each app was seen. A focus donut chart at the top highlights your top apps by cumulative time.

### Worklogs view

Navigate to `/worklogs` to review the worklogs Meridian has drafted from your classified sessions and decide which ones to post to your issue tracker. **Nothing is sent to Jira, Linear, or GitHub until you approve it here — approval is the only gate, and there is no auto-post switch.**

The pipeline that feeds this view is identical for every supported tracker:

<Steps>
<Step title="Draft (every hour)">
The daemon walks the last hour of classified sessions, groups them by matched ticket, and asks the local MLX server to synthesise a short narrative for each task/hour bucket. Each row is written to `pm_worklogs` with `status='draft'` and a snapshot of which provider it should post to (Jira, Linear, or GitHub) — taken from the ticket's `pm_tasks.provider` at draft time.
</Step>
<Step title="Review and edit">
Open `/worklogs`. Every draft is shown with its ticket key, time window, rolled-up duration, the synthesised comment, and a provider badge so you can tell at a glance where it will land. Edit the comment text in-place if you want a different phrasing.
</Step>
<Step title="Approve">
Click **Approve**. The row transitions to `status='approved'`. You can still un-approve before the next post cycle if you change your mind.
</Step>
<Step title="Post (within ~60s)">
The daemon's post loop picks up `approved` rows and dispatches each one based on its provider snapshot:

- **Jira** — `POST /rest/api/3/issue/{key}/worklog` (native worklog, with **Time Spent** + comment).
- **Linear** — `commentCreate` GraphQL mutation (structured comment on the issue).
- **GitHub** — `POST /repos/{owner}/{repo}/issues/{number}/comments` (structured comment on the issue).

On success the row moves to `status='posted'` and the backend's worklog or comment id is stored so the entry can be linked back. Worklogs are idempotent on `(task_key, window_start, window_end)` — re-running the pipeline never produces duplicates.
</Step>
</Steps>

To see the day's drafts without opening the browser:

```bash
meridian worklog-status
```

For the tracker-specific setup that this view depends on, see [Jira](/guides/jira), [GitHub Issues, and Linear](/guides/github-linear).

## Activity categories

Meridian classifies each session into one of ten fixed categories. Each category has a distinct color used consistently across the timeline, the category breakdown chart, and every session card:
Expand Down
70 changes: 57 additions & 13 deletions guides/github-linear.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ sidebarTitle: "GitHub & Linear"
description: "Pull open GitHub or Linear issues into Meridian so coding sessions are automatically classified against the right tickets, with no manual tracking needed."
---

Meridian supports two additional issue trackers alongside Jira: GitHub Issues and Linear. Both work the same way under the hood — Meridian fetches your open issues into the local `pm_tasks` table and uses them as classification targets when it processes each app session. You can enable one, the other, or both at the same time.
Meridian supports two additional issue trackers alongside Jira: GitHub Issues and Linear. Both work the same way under the hood — Meridian fetches your open issues into the local `pm_tasks` table, uses them as classification targets when it processes each app session, and once classification matches a session to an issue it can also **draft a worklog** against that issue. You can enable one, the other, or both at the same time.

Neither GitHub nor Linear exposes a native time-tracking / worklog API, so on these trackers Meridian records a worklog as a **structured comment** on the matched issue: a single Markdown line of the form `**⏱ Worklog — 1h 30m** · 2026-06-02 09:00`, followed by the synthesised narrative of what you did, followed by an HTML-comment machine marker (`meridian-worklog v1 …`) carrying the exact UTC window and seconds so the entry can be parsed back out later. Worklogs are still gated by approval in the dashboard's **Worklogs** view — the same draft → approve → post pipeline as Jira, just with a different final hop. See [Review and approve worklogs](/guides/dashboard#worklogs-view).

<Tabs>
<Tab title="GitHub Issues">
Expand All @@ -14,8 +16,8 @@ Meridian supports two additional issue trackers alongside Jira: GitHub Issues an

## Prerequisites

- A GitHub account with access to your organisation's repositories
- A personal access token (PAT) with at least the `repo` scope
- A GitHub account with access to the organisation (or personal) issues you want to track
- A personal access token (PAT) with **write** access to issue comments — Meridian needs this to post worklog comments after you approve them

## Create a GitHub personal access token

Expand All @@ -27,9 +29,10 @@ Meridian supports two additional issue trackers alongside Jira: GitHub Issues an
Scroll to the bottom of the left sidebar and click **Developer settings**.
</Step>
<Step title="Generate a new token">
Select **Personal access tokens → Fine-grained tokens** (recommended) or **Tokens (classic)**. Click **Generate new token**.
Select **Personal access tokens → Tokens (classic)** or **Fine-grained tokens**. Click **Generate new token**.

For a classic token, enable the **repo** scope. For a fine-grained token, grant **Read-only** access to **Issues** and **Repository metadata** for the repositories Meridian should monitor.
- **Classic token (simplest)** — enable the **`repo`** scope. This single scope covers both reading issues and posting worklog comments, on personal and org-owned repos.
- **Fine-grained token** — grant **Issues: Read and write** on every repository Meridian should monitor (read-only is not enough; Meridian needs write access to add the worklog comment when you approve a draft).
</Step>
<Step title="Copy the token">
Copy the token value before navigating away — GitHub only shows it once.
Expand All @@ -50,13 +53,13 @@ Meridian supports two additional issue trackers alongside Jira: GitHub Issues an
# ~/.meridian/.env

GITHUB_TOKEN=ghp_your_personal_access_token
GITHUB_ORG=your-org-name
GITHUB_ORG=your-org-name # org slug OR your own username

# Optional: limit to specific repos (comma-separated owner/repo pairs)
# GITHUB_REPOS=your-org/api,your-org/web
```

If `GITHUB_REPOS` is omitted, Meridian fetches open issues from all repositories in the organisation that your token can access.
`GITHUB_ORG` is the **issue owner** Meridian should sync — an organisation slug or your own GitHub username (for personal repos). Meridian fetches **open issues assigned to you** under that owner. If `GITHUB_REPOS` is omitted, every repository under the owner that your token can read is included.

## Apply and verify

Expand Down Expand Up @@ -90,11 +93,31 @@ Meridian supports two additional issue trackers alongside Jira: GitHub Issues an

Only open issues from those repositories will be pulled into `pm_tasks`. This is useful when your organisation has many repositories but you only actively work in a subset.

## What "posting a worklog" means on GitHub

GitHub has no native time-tracking API, so when you approve a worklog draft Meridian posts it as a comment on the matched issue via `POST /repos/{owner}/{repo}/issues/{number}/comments`. The comment looks like:

```markdown
**⏱ Worklog — 1h 30m** · 2026-06-02 09:00

Wired the new worklog provider router and migrated existing rows to default to `jira`. Wrote the comment formatter and idempotency check.

<!-- meridian-worklog v1 window=2026-06-02T09:00:00Z/2026-06-02T10:00:00Z seconds=5400 -->
```

In your tracker you will see:

- A new comment on the issue authored by the token's user, with the time-spent line and the synthesised narrative.
- The same comment surfaced on any **Project (v2)** board the issue belongs to — Project cards already show issue comments, so no extra setup is needed.
- A hidden machine marker on the last line that Meridian (and any other tool) can grep for to reconstruct the exact window and seconds later. Worklogs are idempotent on `(task_key, window_start, window_end)` — re-running the pipeline never double-posts.

The same `repo` (classic) or `Issues: Read and write` (fine-grained) scope you configured above is all that's needed — no separate Projects scope is required.

## Troubleshooting

<AccordionGroup>
<Accordion title="401 or 403 errors on startup">
Check that your token has not expired and has the correct scopes. Classic tokens need the `repo` scope; fine-grained tokens need read access to Issues. Regenerate the token in GitHub Settings if needed.
<Accordion title="401 or 403 errors on startup, or when a worklog tries to post">
Check that your token has not expired and has the correct scopes. Classic tokens need the `repo` scope; fine-grained tokens need **Issues: Read and write** (read-only will let issues sync but worklog comments will fail with 403). Regenerate the token in GitHub Settings if needed.
</Accordion>
<Accordion title="pm_tasks is empty for GitHub">
Confirm that `GITHUB_ORG` matches your organisation's login name exactly (case-sensitive). If `GITHUB_REPOS` is set, verify each entry uses the full `owner/repo` format. Your token must have access to at least one repository in the org.
Expand Down Expand Up @@ -147,11 +170,11 @@ Meridian supports two additional issue trackers alongside Jira: GitHub Issues an

LINEAR_API_KEY=lin_api_your_key_here

# Optional: restrict to specific team IDs (comma-separated)
# LINEAR_TEAM_IDS=TEAM1,TEAM2
# Optional: restrict to specific teams (comma-separated team keys or ids)
# LINEAR_TEAM_IDS=ENG,DESIGN
```

If `LINEAR_TEAM_IDS` is omitted, Meridian fetches open issues from all teams your account belongs to.
Meridian sends the key **raw** in Linear's `Authorization` header — there is no `Bearer` prefix (that prefix is for OAuth tokens; personal API keys go in as-is). If `LINEAR_TEAM_IDS` is omitted, Meridian fetches the issues assigned to you across every team your account belongs to.

## Apply and verify

Expand Down Expand Up @@ -183,7 +206,28 @@ Meridian supports two additional issue trackers alongside Jira: GitHub Issues an
LINEAR_TEAM_IDS=ENG,DESIGN
```

Only issues belonging to those teams will be pulled into `pm_tasks`. Find your team IDs in Linear under **Settings → Teams** — each team has an identifier shown in its URL and settings page.
Only issues belonging to those teams will be pulled into `pm_tasks`. Find your team identifiers in Linear under **Settings → Teams** — each team has a short key (e.g. `ENG`) and an internal id; either works.

## What "posting a worklog" means on Linear

Linear has no worklog, time-entry, or "time spent" field in its GraphQL schema. So when you approve a worklog draft, Meridian creates a structured comment on the matched issue via the `commentCreate` mutation:

```graphql
mutation {
commentCreate(input: { issueId: "<issue-uuid>", body: "**⏱ Worklog — 1h 30m** · …" }) {
success
comment { id url }
}
}
```

Meridian first resolves the issue UUID from its human identifier (e.g. `ENG-123`) and then posts the comment. In Linear you will see:

- A new comment on the issue authored by the API key's user, with the **⏱ Worklog — 1h 30m** time-spent line followed by the synthesised narrative.
- The comment counts toward Linear's issue activity feed and is visible in every view that surfaces comments (issue detail, Inbox, Slack mirror if you have it enabled).
- A hidden machine marker on the last line carrying the exact UTC window and seconds, so the entry can be parsed back out programmatically. Worklogs are idempotent on `(task_key, window_start, window_end)` — re-running the pipeline never double-posts.

The personal API key you configured above is the only credential required. Meridian uses the key's `viewer` (the user who created it) as the comment author, so worklog comments are attributed to you.

## Troubleshooting

Expand Down
16 changes: 15 additions & 1 deletion guides/jira.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ description: "Link your Jira Cloud workspace to Meridian so sessions are classif

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. All you need is a Jira API token and three environment variables.

Once classification is wired up, Meridian also **drafts worklogs** against the matched ticket every hour. On Jira, a worklog is posted via Jira's native **worklog REST API** — the same primitive that powers Jira's built-in time tracking, so each posted entry shows up in the ticket's **Work Log** tab with the synthesised narrative as its comment and the rolled-up duration as **Time Spent**. Posting only happens after you approve the draft in the dashboard — see [Review and approve worklogs](/guides/dashboard#worklogs-view) for the shared draft → approve → post pipeline (it works the same way across Jira, Linear, and GitHub).

## Prerequisites

- A Jira Cloud account (Jira Data Center is not supported)
Expand Down Expand Up @@ -51,9 +53,21 @@ JIRA_API_TOKEN=your-api-token-here
```

<Note>
Meridian only reads your Jira tickets for classification. It never creates, modifies, closes, or deletes tickets on your behalf.
Meridian only reads your Jira tickets and writes **worklogs** (Jira's native time-tracking entries) against tickets you've matched. It never creates, modifies, closes, or deletes tickets themselves, and no worklog is posted until you approve it in the dashboard.
</Note>

## What "posting a worklog" means on Jira

When you approve a draft, Meridian calls Jira's `POST /rest/api/3/issue/{key}/worklog` endpoint with:

- **Time spent** — duration of the classified session window, rounded to the nearest minute.
- **Started** — the session start in your local timezone.
- **Comment** — the synthesised narrative of what you actually did during that window (built from screenpipe activity + matched code/commit context).

In Jira you'll see a new entry under the ticket's **Work Log** tab attributed to you, and the ticket's **Time Spent** total will roll up by the worklog's duration. Worklogs are idempotent on `(task_key, window_start, window_end)` — re-running the pipeline never double-posts.

To enable posting at all, the same `JIRA_EMAIL` + `JIRA_API_TOKEN` you set above must be able to **add worklogs** on the relevant projects (the standard "Work on issues" permission in Jira). No extra scopes are needed beyond the API token already configured.

Alternatively, re-run the installer's credential walkthrough to be prompted interactively:

```bash
Expand Down