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