<feed xmlns='http://www.w3.org/2005/Atom'>
<title>soryu/makima, branch fix-task-row-click</title>
<subtitle>soryu-co/soryu mirror</subtitle>
<id>http://src.eirin.xyz/soryu/atom?h=fix-task-row-click</id>
<link rel='self' href='http://src.eirin.xyz/soryu/atom?h=fix-task-row-click'/>
<link rel='alternate' type='text/html' href='http://src.eirin.xyz/soryu/'/>
<updated>2026-05-05T15:30:21+00:00</updated>
<entry>
<title>fix(doc-mode): make task rows clickable and render live transcript</title>
<updated>2026-05-05T15:30:21+00:00</updated>
<author>
<name>soryu</name>
<email>soryu@soryu.co</email>
</author>
<published>2026-05-05T15:30:21+00:00</published>
<link rel='alternate' type='text/html' href='http://src.eirin.xyz/soryu/commit/?id=2de03bc02fefeeb40ea9becaf3b501cc513b1289'/>
<id>urn:sha1:2de03bc02fefeeb40ea9becaf3b501cc513b1289</id>
<content type='text'>
Task rows in the directive sidebar's `tasks/` subfolder were rendered as
inert `&lt;div&gt;` elements with no click handler, and EditorShell had no
branch for `selection.taskId` — so clicking a task did nothing visible.

- StepRow and TaskRow are now `&lt;button&gt;` elements that call
  `onSelect(directiveId, taskId)` and navigate to
  `/directives/&lt;dirId&gt;?task=&lt;taskId&gt;`.
- EditorShell renders DocumentTaskStream with a breadcrumb when
  `selection.taskId` is set (winning over the document path).
- Step rows whose backing task hasn't been spawned yet stay disabled.

Co-Authored-By: Claude Opus 4.7 (1M context) &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>fix(doc-mode): flatten sidebar list + restore right-click context menu (#124)</title>
<updated>2026-05-02T16:47:24+00:00</updated>
<author>
<name>soryu</name>
<email>soryu@soryu.co</email>
</author>
<published>2026-05-02T16:47:24+00:00</published>
<link rel='alternate' type='text/html' href='http://src.eirin.xyz/soryu/commit/?id=cd09103183139788ba4297eaaa6f75d51a154c8a'/>
<id>urn:sha1:cd09103183139788ba4297eaaa6f75d51a154c8a</id>
<content type='text'>
Two regressions reported by the user:

1. The sidebar was grouping contracts under per-status sub-folders
   (active/idle/archived). The user explicitly does not want that —
   they want a flat list with status indicated by a colored dot on the
   right of each row.

2. The right-click context menu on contract rows was missing —
   start/pause/archive/delete/create-PR/update-PR are no longer
   reachable through the UI.

Fixes:

* Drop the SidebarGroup/bucketOf/GROUP_LABEL helpers; replace the
  grouped render with a flat sort by status precedence
  (active → paused → idle → draft → inactive → archived) then alpha
  by title within the same status. The existing dot-color palette is
  unchanged; the dot just moved from the LEFT of the contract title
  to the RIGHT (after the orchestrator-running pulse, when present).

* Wire `onContextMenu` through SidebarProps → DirectiveFolderProps →
  the folder header `&lt;button&gt;`. Page-level state captures the click
  position and the targeted directive; the existing
  DirectiveContextMenu component (start/pause/archive/delete/PR/
  Advance/Cleanup/PickUpOrders) renders on top.

* runAction helper centralises error handling: dispatches the API
  call, refreshes the sidebar list + bumps the document-folder
  refresh nonce on success, surfaces an alert on failure.

* Delete confirms via window.confirm and clears the URL when the
  deleted contract was the one selected.

Co-authored-by: Claude Opus 4.7 (1M context) &lt;noreply@anthropic.com&gt;</content>
</entry>
<entry>
<title>fix(frontend): regenerate pnpm-lock.yaml as v6 format + pin packageManager (#123)</title>
<updated>2026-05-02T15:50:06+00:00</updated>
<author>
<name>soryu</name>
<email>soryu@soryu.co</email>
</author>
<published>2026-05-02T15:50:06+00:00</published>
<link rel='alternate' type='text/html' href='http://src.eirin.xyz/soryu/commit/?id=2c3b0e3926b8c535fb610092301f8621440b51ed'/>
<id>urn:sha1:2c3b0e3926b8c535fb610092301f8621440b51ed</id>
<content type='text'>
Build env's pnpm warned "Ignoring not compatible lockfile" against the v9
lockfile produced by my last regen — older pnpm (8.x and below, which
some build images still ship) only understands v6 lockfiles, and falls
back to "no lockfile" mode which then errors under --frozen-lockfile:

    WARN  Ignoring not compatible lockfile at /app/pnpm-lock.yaml
    ERR_PNPM_NO_LOCKFILE  Cannot install with "frozen-lockfile" because
    pnpm-lock.yaml is absent

Two-pronged fix:

1. Regenerate the lockfile in v6 format using pnpm 8.15.4 via corepack
   (`corepack pnpm@8.15.4 install`). The lockfile now starts with
   `lockfileVersion: '6.0'` again — readable by both old and new pnpm.

2. Pin `packageManager: "pnpm@8.15.4"` in package.json so build envs
   that respect corepack/Volta install the right version automatically
   instead of falling back to whatever's globally installed.

Verified locally with `corepack pnpm@8.15.4 install --frozen-lockfile`
(the CI command). \`tsc --noEmit\` passes.

Co-authored-by: Claude Opus 4.7 (1M context) &lt;noreply@anthropic.com&gt;</content>
</entry>
<entry>
<title>fix(frontend): regenerate corrupted pnpm-lock.yaml (#122)</title>
<updated>2026-05-02T15:33:51+00:00</updated>
<author>
<name>soryu</name>
<email>soryu@soryu.co</email>
</author>
<published>2026-05-02T15:33:51+00:00</published>
<link rel='alternate' type='text/html' href='http://src.eirin.xyz/soryu/commit/?id=5b00a6a91aa8c876e042aca123e053b1e8a4ee99'/>
<id>urn:sha1:5b00a6a91aa8c876e042aca123e053b1e8a4ee99</id>
<content type='text'>
The committed lockfile was a manual frankenstein of pnpm v6 metadata
(`lockfileVersion: '6.0'` + `resolution:` blocks at the top) and v9-style
snapshot entries appended below. pnpm 9 read it as a single packages: map
and tripped on duplicate mapping keys (\`@floating-ui/core@1.7.5\` appeared
twice; same for \`@floating-ui/utils@0.2.11\`, plus dozens of \`@lexical/*\`
and \`@babel/*\` entries duplicated across the v6/v9 sections).

This blew up Docker / Caddy builds:

    ERR_PNPM_BROKEN_LOCKFILE  The lockfile at "/app/pnpm-lock.yaml" is broken:
    duplicated mapping key (688:3)

Regenerated with \`pnpm install --no-frozen-lockfile\` against the existing
package.json — net -1605 / +545 lines. \`pnpm install --frozen-lockfile\` now
succeeds (the CI check), \`tsc --noEmit\` passes, \`vite build\` produces a
clean bundle.

Co-authored-by: Claude Opus 4.7 (1M context) &lt;noreply@anthropic.com&gt;</content>
</entry>
<entry>
<title>feat(doc-mode): + New contract sidebar header + + New ephemeral task per folder (#121)</title>
<updated>2026-05-02T15:11:05+00:00</updated>
<author>
<name>soryu</name>
<email>soryu@soryu.co</email>
</author>
<published>2026-05-02T15:11:05+00:00</published>
<link rel='alternate' type='text/html' href='http://src.eirin.xyz/soryu/commit/?id=08d2ea6a685e248146b30f70421b853ff404b9ad'/>
<id>urn:sha1:08d2ea6a685e248146b30f70421b853ff404b9ad</id>
<content type='text'>
The unified surface didn't expose any way to create a new contract or a
new ephemeral task — the only paths were `/directives/&lt;id&gt;?document=...`
or right-click context menus that no longer existed in the documents-per-
directive sidebar restructure. Two new affordances:

* **Sidebar header gains a "+ New" button** that opens NewContractModal
  (title + goal + optional repository_url). On submit calls
  `useDirectives.create` and navigates the user into the new directive.
  Header label updated from "Documents" to "Contracts" so the button's
  intent reads naturally.

* **Each open directive folder gets a "+ New ephemeral task" button**
  alongside the existing "+ New document" affordance. Opens
  NewEphemeralTaskModal (name + plan), calls the existing
  `createDirectiveTask` API, navigates the user into the new task's
  transcript at `?task=&lt;id&gt;`.

NewContractModal and NewEphemeralTaskModal are local to the page —
mirror the styling of the older NewTaskModal that lived here pre-
restructure. ⌘/Ctrl+Enter submits.

Co-authored-by: Claude Opus 4.7 (1M context) &lt;noreply@anthropic.com&gt;</content>
</entry>
<entry>
<title>build(server): split Dockerfiles, make ML model paths optional (#120)</title>
<updated>2026-05-02T14:26:39+00:00</updated>
<author>
<name>soryu</name>
<email>soryu@soryu.co</email>
</author>
<published>2026-05-02T14:26:39+00:00</published>
<link rel='alternate' type='text/html' href='http://src.eirin.xyz/soryu/commit/?id=70a83104292c4e1fe5f43dd5f50e5214928c8dd6'/>
<id>urn:sha1:70a83104292c4e1fe5f43dd5f50e5214928c8dd6</id>
<content type='text'>
Existing Dockerfile (with LLM/STT/TTS model download) is now `Dockerfile.full`.
The new top-level `Dockerfile` builds a slim image without python, without
huggingface_hub, without the model download step. The slim image is the new
default for users who only want the orchestration surface — the directive
folder UI, the mesh/task system, the API.

## Slim Dockerfile
* No python / huggingface_hub / model downloads.
* Same runtime tooling as `k8s/daemon/Dockerfile` (git, gh CLI, ssh, jq,
  curl, ca-certs, libssl3).
* Embeds the daemon binary at /app/daemon-binaries/makima-linux-x86_64
  for the in-server download endpoint.
* PARAKEET_MODEL_DIR / SORTFORMER_MODEL_PATH / CHATTERBOX_MODEL_DIR are
  intentionally NOT set — Listen and Speak return "ML models not
  configured" if a client tries to use them.

## ML model paths now optional
`ServerArgs.parakeet_model_dir`, `parakeet_eou_dir`, `sortformer_model_path`,
`chatterbox_model_dir` are now `Option&lt;String&gt;` (no defaults). The bin
constructor inspects them: if all four are present, configures
`AppState::new`; if all four are absent, uses the new
`AppState::new_slim()` which leaves `model_config = None`. The lazy load
path in `get_ml_models` already returned a clean error for None.

Speak (TTS) was already optional via `model_config.as_ref()` — still works.

Mixed configurations log a warning and degrade to slim mode.

## Ops note
The old `Dockerfile.full` retains the original behaviour for anyone who
needs STT/diarization/TTS in production. CI still builds the daemon image
from `k8s/daemon/Dockerfile` (untouched).

Co-authored-by: Claude Opus 4.7 (1M context) &lt;noreply@anthropic.com&gt;</content>
</entry>
<entry>
<title>feat: multi-document directives with ephemeral task lifecycle (#119)</title>
<updated>2026-05-02T14:07:33+00:00</updated>
<author>
<name>soryu</name>
<email>soryu@soryu.co</email>
</author>
<published>2026-05-02T14:07:33+00:00</published>
<link rel='alternate' type='text/html' href='http://src.eirin.xyz/soryu/commit/?id=760516b2e7b97fa389fb3902e8d2314eea052ff0'/>
<id>urn:sha1:760516b2e7b97fa389fb3902e8d2314eea052ff0</id>
<content type='text'>
* feat: soryu-co/soryu - makima: Fix folder/file naming and breadcrumb hash bugs

* WIP: heartbeat checkpoint

* WIP: heartbeat checkpoint

* WIP: heartbeat checkpoint

* feat: soryu-co/soryu - makima: Frontend: render multiple documents per directive folder

* WIP: heartbeat checkpoint

* WIP: heartbeat checkpoint

* WIP: heartbeat checkpoint

* Fix DirectiveRevision import in openapi.rs after merge

* Fix document-directives.tsx merge artifacts and add inactive status</content>
</entry>
<entry>
<title>chore(cleanup): Phase 5 contracts removal + tmp directive + 30-day expiry + scroll fix (#118)</title>
<updated>2026-05-01T22:56:51+00:00</updated>
<author>
<name>soryu</name>
<email>soryu@soryu.co</email>
</author>
<published>2026-05-01T22:56:51+00:00</published>
<link rel='alternate' type='text/html' href='http://src.eirin.xyz/soryu/commit/?id=e11759447b1ac00becfb1e979e488f7f9c9cf478'/>
<id>urn:sha1:e11759447b1ac00becfb1e979e488f7f9c9cf478</id>
<content type='text'>
Sweeping cleanup across the surface and the wire. Net: -14k LOC of legacy
contracts code, plus the tmp/scroll/UX fixes the user asked for.

## Sidebar/editor independent scroll
Replace `height: calc(100vh - 80px)` (which assumed an 80px masthead and
quietly clipped or pushed the whole page below the fold when the masthead
was taller) with `h-screen + overflow-hidden` on the page root and proper
`flex-1 min-h-0` sizing on `&lt;main&gt;`. Sidebar and editor pane now manage
their own scroll independently; the page itself never scrolls.

Same fix in /tmp/:taskId.

## tmp directive — real backing for orphans/ephemerals

New migration `20260501100000_tmp_directive_and_clear_orphans.sql`:
  * Adds `directives.is_tmp` BOOLEAN NOT NULL DEFAULT false.
  * Partial unique index `(owner_id) WHERE is_tmp` — at most ONE tmp
    directive per owner.
  * Hard-deletes every existing orphan task (`directive_id IS NULL`).
    Per the user spec: "ALSO there are TOO MANY old tasks in tmp, we
    need to remove all of them as well."

New repository helpers:
  * `get_or_create_tmp_directive(pool, owner_id) -&gt; Directive`
    INSERT ON CONFLICT DO NOTHING + fallback SELECT, race-safe.
  * `list_all_tmp_directives` — drives the expiry sweep.
  * `delete_expired_tmp_tasks(tmp_directive_id) -&gt; u64`.
  * `list_tmp_tasks_for_owner` (replaces `list_orphan_tasks_for_owner`).

`mesh::create_task`: every top-level task must have a directive. If a
caller doesn't supply `directive_id` and isn't a subtask, attach to the
caller's tmp directive (auto-creating it on first use).

`list_directives_for_owner` filters out `is_tmp=true` so the scratchpad
directive doesn't pollute the contract list — surfaced via the sidebar's
`tmp/` folder instead.

## 30-day expiry on tmp tasks

New `phase_tmp_expiry` in the directive reconciler. Throttled to once per
hour: enumerates every tmp directive, calls `delete_expired_tmp_tasks`,
logs the count. The actual delete is `WHERE created_at &lt; NOW() - INTERVAL
'30 days'` and is fast on the existing index. Subtasks die via FK cascade.

## Phase 5 — contracts removed

### Frontend
Deleted entire `/contracts` surface:
  * routes: `contracts.tsx`, `contract-file.tsx`
  * components/contracts: ContractList, ContractDetail, ContractCliInput,
    ContractContextMenu, CommandModePanel, PhaseBadge, PhaseHint,
    PhaseDeliverablesPanel, PhaseProgressBar, QuickActionButtons,
    RepositoryPanel, TaskDerivationPreview
  * (Kept `PhaseConfirmationModal` — used outside the contracts surface
    by `TaskOutput` and `PhaseConfirmationNotification`.)
  * Routes deregistered from `main.tsx`; nav entry removed from
    `NavStrip`.

### Backend handlers
Deleted: `contracts.rs` (2.4k LOC), `contract_chat.rs` (3.2k LOC),
`contract_daemon.rs` (~940 LOC), `contract_discuss.rs` (~590 LOC),
`transcript_analysis.rs` (~690 LOC). All `/api/v1/contracts/*` routes
deregistered. OpenAPI entries dropped. Module declarations removed from
`server/handlers/mod.rs`.

### CLI
Removed `makima contract` and `makima supervisor` subcommands. Deleted
`daemon/cli/contract.rs` and `daemon/cli/supervisor.rs`. Bin dispatch
trimmed (~377 LOC).

### Orchestrator
Removed the contract-spawn path from `phase_execution`
(`spawn_step_contract` and its caller). `directive_steps.contract_type`
now logs a warning and falls through to standalone-task spawn. Column
itself stays — old data still reads, just no longer triggers a
contract+supervisor spawn.

### TUI
`Action::PerformCreateContract` is now a no-op that surfaces a status
message: "Contracts have been removed. Use directives instead." The TUI
form is dead code pending a wider refresh.

## Out of scope (deliberately left)

* Contracts DB tables (`contracts`, `contract_repositories`,
  `contract_chat_history`, `contract_events`, `contract_templates`) are
  retained for historical data + because some peripheral code still
  joins to them in TaskSummary queries.
* `mesh_supervisor` handlers are retained — they aren't only used by
  contracts (some mesh-level supervisor behaviour persists), and the
  cross-cutting cleanup is bigger than this PR.
* `directive_steps.contract_type` column itself isn't dropped; just no
  longer functional.

Co-authored-by: Claude Opus 4.7 (1M context) &lt;noreply@anthropic.com&gt;</content>
</entry>
<entry>
<title>feat(doc-mode): unified surface — ephemeral tasks, tmp/, /exec redirect, palette, SWR (#117)</title>
<updated>2026-05-01T17:06:38+00:00</updated>
<author>
<name>soryu</name>
<email>soryu@soryu.co</email>
</author>
<published>2026-05-01T17:06:38+00:00</published>
<link rel='alternate' type='text/html' href='http://src.eirin.xyz/soryu/commit/?id=80085c7cfa9d679ed3e3fd54a7d55fa8ab1addef'/>
<id>urn:sha1:80085c7cfa9d679ed3e3fd54a7d55fa8ab1addef</id>
<content type='text'>
Phases 1-3 of the unified-surface plan, bundled per the user's request.
The directive document/folder UI is now the canonical place to interact
with makima; legacy /exec is subsumed by routing redirects, /contracts is
already hidden in nav, and orphan tasks surface under a top-level tmp/
pseudo-folder. Phase 4 (porting contract-only features) was confirmed
out of scope; Phase 5 (deleting the contracts code) is a follow-up.

## Backend

- New migration `20260501000000_archive_existing_contracts.sql` flips
  every legacy contract to `archived` so /contracts is read-only history.
- New endpoint `POST /api/v1/directives/{id}/tasks` creates an ephemeral
  task — `directive_id` set, `directive_step_id` NULL, repo/branch
  inherited from the directive. Reuses `create_task_for_owner`.
- New endpoint `GET /api/v1/directives/{id}/tasks` lists ephemeral tasks
  attached to a directive (drives the per-folder ephemeral group).
- `GET /api/v1/mesh/tasks?orphan=true` returns top-level tasks with no
  `directive_id` AND no `parent_task_id` — backs the sidebar's tmp/.
- New repo helpers `list_ephemeral_directive_tasks_for_owner` and
  `list_orphan_tasks_for_owner`.
- The existing `mesh_merge` endpoints are reused as-is for ephemeral
  task merge (no new merge logic needed).

## Frontend

### Sticky composer + auto-scroll fix (`DocumentTaskStream.tsx`)
- Sticky comment composer pinned to viewport bottom; padding compensates
  so the last entry isn't hidden behind it.
- `autoScroll` now resumes when the user scrolls back within 80px of
  the bottom (previously stuck off forever after a single scroll-up).
- Floating "↓ Jump to latest" chip when the user has scrolled away.
- Action header strip: explicit Stop / Send / Open-in-task-page +
  conditional "Merge to base ↗" button on ephemeral terminal tasks.
- Module-level cache of historical entries by taskId so re-selecting a
  task you've viewed renders instantly while a fresh fetch runs.

### Sidebar (`document-directives.tsx`)
- Top-level `tmp/` folder: orphan tasks, polled every 5s.
- Per-directive `tasks/` subfolder now also surfaces ephemeral tasks
  (lazily fetched on folder open) with a distinct asterisk-on-terminal
  icon (`EphemeralTaskIcon`).
- Inline hover-action chips on each directive folder header: Start /
  Pause / PR / +New task. Right-click menu still works as a power-user
  fallback.
- "Now executing" amber strip in the editor pane: surfaces the live
  orchestrator/completion/running-step task with a one-click jump.
- Inline `+ New task` modal (name + plan); on submit calls
  `createDirectiveTask` and navigates into the freshly-spawned task.
- New `EphemeralAwareTaskStream` wrapper passes `ephemeral` and
  `status` to `DocumentTaskStream` so the merge button only shows when
  the selected task is genuinely an ephemeral spinoff in a terminal
  state. Step-spawned tasks merge via the directive's PR completion.

### SWR cache (`useDirectives.ts`)
- Module-level `listCache` and per-id `detailCache` (mirrors the pattern
  in `useUserSettings.ts`). Mounting the hook renders the cache value
  immediately if present and kicks a background refresh; subscribers see
  the new value when it lands. Cuts perceived navigation latency to
  near-zero on warm cache hits.

### QuickSwitcher (`QuickSwitcher.tsx`, new)
- IntelliJ-style double-Shift command palette mounted at app root.
- Listens at the document level for two `Shift` keydowns within 300ms
  with no other key in between; ignores while focus is in an
  input/textarea so capitalising letters doesn't pop the palette.
- Searches across directives + their tasks (orchestrator/completion/
  steps/ephemerals) + orphan tmp tasks. Fuzzy matches on title.
- Eagerly loads task details for the first 20 directives on open so
  searches don't block on per-directive fetches.

### Routing (`main.tsx` + `exec-redirect.tsx` + `tmp.tsx`)
- New `ExecRedirect` wrapper at `/exec/:id`: when documentMode is on
  AND the task has a `directiveId`, replaces the URL with
  `/directives/&lt;directiveId&gt;?task=&lt;taskId&gt;`. Otherwise renders the
  legacy `MeshPage` as before.
- New `/tmp/:taskId` route renders `DocumentTaskStream` standalone for
  orphan tasks, with the masthead and a `tmp / &lt;slug&gt;` breadcrumb.

Co-authored-by: Claude Opus 4.7 (1M context) &lt;noreply@anthropic.com&gt;</content>
</entry>
<entry>
<title>fix(doc-mode): root-walk goal serializer + roundtrip-confirmed draft drop, plus richer context menus (#114)</title>
<updated>2026-04-30T22:26:10+00:00</updated>
<author>
<name>soryu</name>
<email>soryu@soryu.co</email>
</author>
<published>2026-04-30T22:26:10+00:00</published>
<link rel='alternate' type='text/html' href='http://src.eirin.xyz/soryu/commit/?id=6d922307223d12f436b229d4c4b29b8835b93b6c'/>
<id>urn:sha1:6d922307223d12f436b229d4c4b29b8835b93b6c</id>
<content type='text'>
## The data-loss bug

User reported "even after clicking Save now I have lost my doc". Two causes:

1. **GoalChangePlugin only read children[1]** — it captured edits to the
   single goal paragraph but silently dropped any typing that landed in
   the trailing paragraph below the StepsBlock (or in extra paragraphs the
   user had inserted). pendingGoalRef stayed at the persisted value, Save
   now fired empty/stale content, the doc was overwritten.

2. **fireSave dropped localStorage immediately on save success.** If the
   save persisted the wrong/empty content, the draft (which had the real
   content) was already gone — no recovery path.

## Fixes

### Capture all body content
New `serializeGoalFromRoot` walks the entire root, skips only the H1 title
and the StepsBlock decorator, and emits multi-paragraph markdown joined by
blank lines. `GoalChangePlugin` and `fireSave` both call it now. Seed code
splits an existing multi-paragraph goal back into ParagraphNodes on load.

### Read directly from the editor at save time
`fireSave` now reads pendingGoalRef AND consults the live editor state via
`editor.getEditorState().read()`. If anything went wrong with OnChangePlugin
(which is rare, but possible — and was eating typing for many users), the
save still picks up the actual document body.

### Defensive pre-save flush
Before talking to the backend, `fireSave` writes the value to localStorage.
If the network fails, the page closes mid-flight, or anything else goes
sideways, the draft survives.

### Roundtrip-confirmed draft cleanup
We no longer drop the localStorage draft inside `fireSave`. Instead a new
effect watches `directive.goal` and clears the draft only when:
  lastSavedValueRef === directive.goal === pendingGoalRef.current
i.e. only when the polled state confirms our save persisted AND the user
hasn't typed anything new in the meantime.

## Question notifications respect document mode

`SupervisorQuestionNotification` and `PhaseConfirmationToast` now route to
`/directives/&lt;id&gt;?task=&lt;taskId&gt;` (the doc-mode surface) when the user has
documentMode on AND the question carries a directiveId. Falls back to the
old `/exec/:taskId` route for non-doc-mode users.

## Richer directive folder context menu

In addition to start/pause/archive/delete/go-to-PR/new-draft we now expose:
  - Advance DAG
  - Plan orders
  - Clean up
  - Create / Update PR
All optional callbacks; the legacy tabular UI is unaffected.

## Richer task row context menu

In addition to interrupt/complete/fail/skip we now expose:
  - Send message — browser prompt → sendTaskMessage (same wire as the
    inline comment box)
  - Open in task page — navigates to /exec/:taskId for the full task UI
    (worktree diff viewer, checkpoint controls, etc.)

Co-authored-by: Claude Opus 4.7 (1M context) &lt;noreply@anthropic.com&gt;</content>
</entry>
</feed>
