From 617034b0d453ca68091f188fd1a423bf1da5c20d Mon Sep 17 00:00:00 2001
From: "mintlify[bot]" <109931778+mintlify[bot]@users.noreply.github.com>
Date: Tue, 2 Jun 2026 07:12:39 +0000
Subject: [PATCH] docs: describe worklog posting on Jira, Linear, and GitHub
---
guides/dashboard.mdx | 35 ++++++++++++++++++++
guides/github-linear.mdx | 70 ++++++++++++++++++++++++++++++++--------
guides/jira.mdx | 16 ++++++++-
3 files changed, 107 insertions(+), 14 deletions(-)
diff --git a/guides/dashboard.mdx b/guides/dashboard.mdx
index 67630c8..21a301e 100644
--- a/guides/dashboard.mdx
+++ b/guides/dashboard.mdx
@@ -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:
+
+
+
+ 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.
+
+
+ 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.
+
+
+ Click **Approve**. The row transitions to `status='approved'`. You can still un-approve before the next post cycle if you change your mind.
+
+
+ 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.
+
+
+
+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:
diff --git a/guides/github-linear.mdx b/guides/github-linear.mdx
index f93d1c6..0171e05 100644
--- a/guides/github-linear.mdx
+++ b/guides/github-linear.mdx
@@ -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).
@@ -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
@@ -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**.
- 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).
Copy the token value before navigating away — GitHub only shows it once.
@@ -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
@@ -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.
+
+
+ ```
+
+ 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
-
- 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.
+
+ 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.
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.
@@ -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
@@ -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: "", 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
diff --git a/guides/jira.mdx b/guides/jira.mdx
index 8b82fb1..72c485b 100644
--- a/guides/jira.mdx
+++ b/guides/jira.mdx
@@ -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)
@@ -51,9 +53,21 @@ JIRA_API_TOKEN=your-api-token-here
```
- 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.
+## 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