From 3be998b372e0a0ed4a466fb09e5bbc7e613c0fb9 Mon Sep 17 00:00:00 2001
From: "mintlify[bot]" <109931778+mintlify[bot]@users.noreply.github.com>
Date: Tue, 2 Jun 2026 07:12:19 +0000
Subject: [PATCH 1/2] docs: document approval-gated worklog flow and Worklogs
view
---
docs.json | 1 +
guides/worklogs.mdx | 141 ++++++++++++++++++++++++++++++++++++++++++++
reference/cli.mdx | 43 ++++++++++++++
3 files changed, 185 insertions(+)
create mode 100644 guides/worklogs.mdx
diff --git a/docs.json b/docs.json
index 2645d1b..6768dd7 100644
--- a/docs.json
+++ b/docs.json
@@ -43,6 +43,7 @@
"guides/github-linear",
"guides/mcp-setup",
"guides/dashboard",
+ "guides/worklogs",
"guides/querying-data"
]
},
diff --git a/guides/worklogs.mdx b/guides/worklogs.mdx
new file mode 100644
index 0000000..909391b
--- /dev/null
+++ b/guides/worklogs.mdx
@@ -0,0 +1,141 @@
+---
+title: "Review and Approve Worklogs Before They Post to Jira"
+sidebarTitle: "Worklogs"
+description: "Use the Worklogs view in the Meridian dashboard to review, edit, and approve drafted worklogs — the only path that posts time to your tracker."
+---
+
+Meridian's PM-worklog stage synthesises one worklog per ticket per hour from your classified sessions. **Nothing reaches Jira automatically.** The daemon only ever *drafts* worklogs; you review, edit, and approve each one in the dashboard's **Worklogs** view, and a separate post sweep writes the approved entries to Jira within about a minute.
+
+Use this guide when you want to keep an automated record of your time without giving up the final say over what lands on a ticket.
+
+## When to use this
+
+Turn to the Worklogs view if you want to:
+
+- Capture per-ticket time logs from your real activity without writing them by hand.
+- Keep a human in the loop — every comment posted to Jira is something you explicitly approved.
+- Edit auto-generated comments before they go out, or dismiss drafts that don't represent useful work.
+
+The flow assumes Jira is already connected. See [Connect Meridian to Jira Cloud](/guides/jira) if you haven't set up the connector yet.
+
+## The drafted → approved → posted state machine
+
+Every worklog moves through a small set of states:
+
+```
+drafted ──(UI edit)──▶ drafted ──(UI approve)──▶ approved ──(post sweep)──▶ posted
+ │
+ terminal (empty / < 60s) └──▶ failed
+```
+
+| State | What it means |
+|---|---|
+| `drafted` | The hourly driver synthesised a worklog from your sessions. It is **not** in Jira. Edit it, approve it, or dismiss it. |
+| `approved` | You approved the draft in the Worklogs view. It is queued for the next post sweep but has **not** been posted yet. You can still un-approve it to hold it back. |
+| `posted` | The post sweep wrote the comment to Jira. The state is terminal; Meridian records the Jira worklog ID alongside the row. |
+| `skipped` | You dismissed the draft. It will not be posted and the hour is considered handled. |
+| `failed` | The post sweep tried to write to Jira and got an error (auth, network, validation). The error is shown on the card; fix the cause and re-approve to retry. |
+
+Approval is the **only** way a worklog reaches your tracker. A driver re-run can never clobber an `approved` or `posted` row, so a human decision is never silently overwritten.
+
+
+ `time_spent` always comes from your actual idle-discounted activity for the hour (capped at one hour). The language model writes the comment, not the duration.
+
+
+## The Worklogs view
+
+Open the dashboard at [http://localhost:3000](http://localhost:3000) and select **Worklogs** in the sidebar (keyboard shortcut `4`).
+
+The header shows the day you're reviewing and a running count of drafts, approved, and posted worklogs. Use the `←` / `→` arrows to step through previous days; you can't step past today.
+
+Each worklog is rendered as a card containing:
+
+- The ticket key, the hour the worklog covers, and the time spent in that hour.
+- A confidence ring and any risk flags raised during synthesis (e.g. `low_confidence`, `thin_evidence`).
+- The editable comment that will be posted to Jira.
+- Optional supporting detail — the underlying bullets and suggested next steps — collapsed by default behind **show supporting detail**.
+- The current state badge (`Draft`, `Approved`, `Posted`, `Dismissed`, `Failed`).
+
+The view polls every 30 seconds, so when the post sweep flips an `approved` row to `posted` (or `failed`) you'll see it update without reloading.
+
+## Approving, editing, and dismissing drafts
+
+Each card on a non-posted worklog has three actions:
+
+
+
+ Marks the worklog as `approved`. The post sweep picks it up within about 60 seconds and writes it to Jira.
+
+
+ Opens the comment in an inline textarea. Saving re-drafts the worklog (you'll need to approve it again before it posts). The `edited` badge appears on cards you've touched.
+
+
+ Marks the worklog as `skipped`. It will not be posted and won't show up in the unapproved queue again.
+
+
+
+If a card is already `approved` but hasn't posted yet, the primary button becomes **Hold (un-approve)** so you can pull it back before the next sweep.
+
+When every draft on the page looks good, use **Approve all N drafts** at the top of the view to approve them in one click. Empty drafts (no synthesised comment) are skipped automatically.
+
+## The post sweep
+
+A background sweep in the daemon runs approximately every 60 seconds and posts every `approved` worklog it finds to Jira, marking each one `posted` on success or `failed` (with the error message) otherwise. This sweep is the **sole** path that writes to your tracker.
+
+If you can't wait for the next sweep — for example, you just approved a batch at the end of the day and want them all posted now — run:
+
+```bash
+meridian worklog-post-approved
+```
+
+The command runs exactly the same sweep on demand and exits when it's done.
+
+## Inspecting the day from the CLI
+
+For a no-SQL summary of a given day, including hours done, pending, and stuck, plus rows grouped by state and a flagged list of low-confidence or risk-flagged drafts to inspect first, use:
+
+```bash
+meridian worklog-status --day 2026-05-30
+```
+
+Omit `--day` to see today.
+
+## Configuration
+
+The PM-worklog stage runs inside the Rust daemon and uses the MLX server's synthesis endpoint to write each draft comment. Beyond connecting Jira, you typically don't need to set anything. A few optional tunables in `~/.meridian/.env`:
+
+| Variable | Default | Purpose |
+|---|---|---|
+| `PM_WORKLOG_INTERVAL_HOURS` | `1.0` | How often the driver runs a drafting pass. Clamped to a 60-second floor. |
+| `PM_WORKLOG_MIN_CONFIDENCE` | `0.65` | Below this, drafts are flagged `low_confidence` for extra scrutiny. |
+| `PM_WORKLOG_READINESS_AGING_MIN` | `90` | Maximum minutes the driver will wait for an hour to settle before drafting anyway. |
+
+
+ There is no environment variable that enables automatic posting. The previous `PM_WORKLOG_POST_ENABLED` switch has been removed — approval in the Worklogs view is the only gate.
+
+
+## Troubleshooting
+
+
+
+ Drafts are produced once an hour by the daemon and only for tickets you have classified sessions against. Confirm with:
+
+ ```bash
+ meridian worklog-status
+ ```
+
+ If `hours done` is `0`, check that `meridian status` shows the daemon and MLX server running, and that Jira is connected (`meridian doctor`).
+
+
+ The post sweep runs roughly every 60 seconds. If a row hasn't posted after a minute or two, run the sweep manually to surface any error:
+
+ ```bash
+ meridian worklog-post-approved
+ ```
+
+ If the row flips to `Failed`, the card will display the underlying Jira error. Fix the cause (commonly a stale API token or a closed ticket) and approve again to retry.
+
+
+ If synthesis couldn't produce a useful comment — for example, the hour had too little signal — the draft renders as `(empty — nothing to post; edit to add a comment)`. Approve is disabled for empty drafts; either edit the comment yourself or dismiss the card.
+
+
diff --git a/reference/cli.mdx b/reference/cli.mdx
index db9553e..55c37fc 100644
--- a/reference/cli.mdx
+++ b/reference/cli.mdx
@@ -187,6 +187,49 @@ Without Screen Recording permission, screenpipe cannot capture frames and Meridi
+
+
+```bash
+meridian pm-worklog [--day YYYY-MM-DD]
+```
+
+Runs one pass of the PM-worklog drafter on the given day (defaults to today). For each ticket with classified sessions in a settled hour, Meridian collects the activity, calls the MLX server's synthesis endpoint, grounds the result against the evidence, and writes a `drafted` row to the database. **This command never posts to Jira** — every draft awaits approval in the dashboard's Worklogs view.
+
+The hourly daemon driver runs the same logic automatically. Run this command manually when you want to backfill drafts for an earlier day or replay drafting after fixing classification.
+
+See [Review and Approve Worklogs](/guides/worklogs) for the full approval flow.
+
+
+
+
+
+```bash
+meridian worklog-post-approved
+```
+
+Runs the post sweep on demand: finds every worklog you have marked `approved` in the dashboard's Worklogs view and writes it to Jira, flipping the row to `posted` (or `failed` with the underlying error). This is the same sweep the daemon runs automatically every ~60 seconds — use this command when you want to flush approvals immediately rather than wait for the next tick.
+
+This is the **only** path Meridian uses to write worklogs to Jira.
+
+
+
+
+
+```bash
+meridian worklog-status [--day YYYY-MM-DD]
+```
+
+Prints a human-readable summary of the PM-worklog stage for the given day (defaults to today), without touching SQL:
+
+- Hours done, pending, and stuck for the day.
+- Counts of worklogs by state (`drafted`, `approved`, `posted`, `skipped`, `failed`).
+- A per-ticket table with the synthesised Jira comment.
+- A **flagged** list of low-confidence or risk-flagged drafts to inspect before approving.
+
+Run this command to triage the day before opening the Worklogs view.
+
+
+
```bash
From 6e19c1e890c138c00d40bda116acd574d6a0ee09 Mon Sep 17 00:00:00 2001
From: "mintlify[bot]" <109931778+mintlify[bot]@users.noreply.github.com>
Date: Thu, 4 Jun 2026 07:15:55 +0000
Subject: [PATCH 2/2] docs: document dismiss attribution picker in Worklogs
review
---
guides/worklogs.mdx | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/guides/worklogs.mdx b/guides/worklogs.mdx
index 909391b..3094559 100644
--- a/guides/worklogs.mdx
+++ b/guides/worklogs.mdx
@@ -70,7 +70,7 @@ Each card on a non-posted worklog has three actions:
Opens the comment in an inline textarea. Saving re-drafts the worklog (you'll need to approve it again before it posts). The `edited` badge appears on cards you've touched.
- Marks the worklog as `skipped`. It will not be posted and won't show up in the unapproved queue again.
+ Marks the worklog as `skipped` after asking *where the time should have gone* — see [Dismissing a draft and correcting attribution](#dismissing-a-draft-and-correcting-attribution).
@@ -78,6 +78,22 @@ If a card is already `approved` but hasn't posted yet, the primary button become
When every draft on the page looks good, use **Approve all N drafts** at the top of the view to approve them in one click. Empty drafts (no synthesised comment) are skipped automatically.
+## Dismissing a draft and correcting attribution
+
+When you click **Dismiss** on a draft, the card expands into an attribution picker asking *"Where should this time have gone?"*. You're not just rejecting the worklog — you're labelling what the classifier got wrong. Pick one of:
+
+- **Another open ticket** — the work belonged to a different task. Meridian records the corrected `task_key` as the ground truth for that hour.
+- **Untracked / personal** — the activity wasn't billable work at all. Meridian records that the hour should not have produced any worklog.
+- **Just dismiss — not sure** — you don't have a clear answer; the worklog is dismissed with no attribution label.
+
+After choosing, click **Dismiss worklog** to confirm. The worklog moves to `skipped` and the correction is stored alongside the existing edit history as immutable review feedback.
+
+Every approve, reject, and un-approve action is recorded the same way — not just edits — so Meridian retains a complete history of how each draft was reviewed even though only the latest state is shown on the card. This feedback feeds the classifier evaluation pipeline; over time, drafts you reject with corrections help Meridian get attribution right on similar sessions.
+
+
+ No external system is told about the correction — it's stored locally in your Meridian database for evaluation only.
+
+
## The post sweep
A background sweep in the daemon runs approximately every 60 seconds and posts every `approved` worklog it finds to Jira, marking each one `posted` on success or `failed` (with the error message) otherwise. This sweep is the **sole** path that writes to your tracker.