<feed xmlns='http://www.w3.org/2005/Atom'>
<title>soryu/makima, branch master</title>
<subtitle>soryu-co/soryu mirror</subtitle>
<id>http://src.eirin.xyz/soryu/atom?h=master</id>
<link rel='self' href='http://src.eirin.xyz/soryu/atom?h=master'/>
<link rel='alternate' type='text/html' href='http://src.eirin.xyz/soryu/'/>
<updated>2026-05-18T00:21:30+00:00</updated>
<entry>
<title>chore: drop legacy contracts + supervisor task-grouping (#136)</title>
<updated>2026-05-18T00:21:30+00:00</updated>
<author>
<name>soryu</name>
<email>soryu@soryu.co</email>
</author>
<published>2026-05-18T00:21:30+00:00</published>
<link rel='alternate' type='text/html' href='http://src.eirin.xyz/soryu/commit/?id=f240675da99bc7705e473b8f70a2628812aa4c10'/>
<id>urn:sha1:f240675da99bc7705e473b8f70a2628812aa4c10</id>
<content type='text'>
The contracts table, supervisor task type, and all their backing
machinery have been inert for several PRs. The directives system reads
its own active contract body for spec text, and PR #135 removed the
last LLM surface that spawned supervisors.

This PR wipes the dead surface in one shot — the user authorised a DB
wipe, so the migration drops every legacy table with CASCADE rather
than carrying forward stub rows. Net change: −12k LOC across handlers,
repository, state, models, the TUI, and the listen module.

What's gone:
- contracts, contract_chat_*, contract_events, contract_repositories,
  contract_type_templates tables.
- supervisor_states, supervisor_heartbeats tables.
- mesh_chat_conversations, mesh_chat_messages tables.
- tasks.contract_id/is_supervisor/supervisor_task_id/supervisor_worktree_task_id columns.
- directive_steps.contract_id/contract_type columns.
- files.contract_id/contract_phase columns.
- history_events.contract_id/phase columns.
- The Contract/Supervisor/MeshChat handler + model + repository
  surface, plus the daemon TUI views that read them.
- The standalone listen.rs websocket handler (orphaned with the LLM).

What stays:
- mesh_supervisor handler: trimmed to just the questions + orders
  backchannel used by `makima directive ask` / `create-order` (kept
  the URL prefix for CLI client compat).
- directive_documents (the user-facing "contracts" surface).
- pending_questions in-memory state for the directive Ask flow.

cargo check, cargo test --lib (68 passed), tsc, and vite build all
clean.

Co-authored-by: Claude Opus 4.7 (1M context) &lt;noreply@anthropic.com&gt;</content>
</entry>
<entry>
<title>chore: remove LLM module + all dependent surfaces (#135)</title>
<updated>2026-05-17T20:23:20+00:00</updated>
<author>
<name>soryu</name>
<email>soryu@soryu.co</email>
</author>
<published>2026-05-17T20:23:20+00:00</published>
<link rel='alternate' type='text/html' href='http://src.eirin.xyz/soryu/commit/?id=0d996cf7590e3e52f424859c7d6f0e68640f119e'/>
<id>urn:sha1:0d996cf7590e3e52f424859c7d6f0e68640f119e</id>
<content type='text'>
Wholesale removal of the LLM integration layer. ~14,200 LOC deleted
across backend and frontend. All chat-driven UIs go with it.

## Backend
- Delete `src/llm/` (7,400 LOC): claude/groq clients, contract_tools,
  contract_evaluator, discuss_tools, mesh_tools, phase_guidance,
  task_output, templates, markdown round-trip, tools, transcript_analyzer.
- Delete handlers wholly dependent on LLM:
  - `chat.rs` (file-level LLM chat at /files/{id}/chat)
  - `mesh_chat.rs` (mesh &amp; task LLM chat + history)
  - `templates.rs` (/contract-types listing)
- Strip LLM uses from `mesh_daemon.rs`:
  - `compute_action_directive` (used phase_guidance::check_deliverables_met
    to nudge supervisors with "all tasks done" messages). The auto-PR
    path below still fires when all tasks finish, so no behaviour lost.
  - `crate::llm::markdown_to_body` → inline 1-line replacement that
    wraps markdown content in a single BodyElement::Markdown. The
    editor re-parses on display, so round-trip is preserved.
- Drop routes: /files/{id}/chat, /mesh/chat, /mesh/chat/history,
  /mesh/tasks/{id}/chat, /contract-types.
- Drop the matching openapi registrations.

## Frontend
- Delete components that were LLM-only:
  - `mesh/UnifiedMeshChatInput.tsx`
  - `listen/DiscussContractModal.tsx`
  - `listen/TranscriptAnalysisPanel.tsx`
  - `listen/ContractPickerModal.tsx`
  - `files/CliInput.tsx`
- Delete the entire /listen page (its primary value-add was
  voice → LLM analysis → contract creation; without LLM the page is
  just a transcript display with no obvious user purpose).
- Delete `hooks/useMeshChatHistory.ts` and `lib/listenApi.ts`
  (transcript-analysis API client to the already-Phase-5-removed
  listen handlers).
- Strip api.ts of LLM exports: LlmModel, ChatMessage/Request/Response,
  UserQuestion/Answer, chatWithFile, MeshChat* types &amp; functions,
  getMeshChatHistory, clearMeshChatHistory, chatWithMeshContext,
  ContractTypeTemplate, listContractTypes, chatWithContract,
  getContractChatHistory, clearContractChatHistory, discussContract,
  PhaseDefinition, DeliverableDefinition.
- mesh.tsx: drop UnifiedMeshChatInput render + the chatContext memo +
  handleTaskUpdatedFromCli (only consumer was the input).
- files.tsx: drop CliInput render + handleGenerateFromElement +
  handleBodyUpdate + handleClearFocus + suggestedPrompt state (all
  CliInput-only).
- NavStrip: drop the /listen link.
- main.tsx: drop the /listen route.

## Net diff: 37 files changed, 58 insertions, 14,281 deletions.

Co-authored-by: Claude Opus 4.7 (1M context) &lt;noreply@anthropic.com&gt;</content>
</entry>
<entry>
<title>feat(directives): strict orchestration flow + sidebar overhaul + task page rewrite (#134)</title>
<updated>2026-05-16T18:56:21+00:00</updated>
<author>
<name>soryu</name>
<email>soryu@soryu.co</email>
</author>
<published>2026-05-16T18:56:21+00:00</published>
<link rel='alternate' type='text/html' href='http://src.eirin.xyz/soryu/commit/?id=ce29ae801bcc5a0ba76d5a8d1565242ab267a47d'/>
<id>urn:sha1:ce29ae801bcc5a0ba76d5a8d1565242ab267a47d</id>
<content type='text'>
End-to-end rewrite addressing the issues from the user's UX review.
The system now feels like a daemon-orchestration tool: lock a contract
and the orchestrator just goes; PR raised → auto-ship → reopen for
amendments. The sidebar tree shows real entities only (no duplicates,
no inline action buttons polluting the file list), and every entity
gets a right-click context menu. Task page matches the old /exec
layout (diff on the left, feed + composer on the right).

## Backend — strict lifecycle (the orchestrator-never-spawned bug)

Root cause: `phase_planning()` gates on `directive.status='active'`, but
`start_contract()` only flipped the contract row — the parent directive
stayed in whatever state it was. So locking a contract did nothing
visible.

Fix: contract lifecycle now drives directive status in the same
transaction.

  start_contract   → if contract becomes active, flip directive
                     draft|paused|idle|inactive → active
  pause_contract   → after promote, if no active contract left,
                     directive → paused
  complete_contract→ after promote, if no active left, directive →
                     inactive (also fires on auto-ship from PR detect)
  unlock_contract  → if was active and no active left, directive →
                     paused
  reopen_contract  → NEW. shipped → active. Directive → active,
                     orchestrator_task_id/pr_url/pr_branch cleared so
                     the reconciler spawns a fresh planner. The
                     planner reads get_latest_merged_revision and
                     frames the new plan as an amendment.

handlers::directive_documents lifts state.kick_directive_reconciler()
into run_contract_transition so every successful transition wakes the
reconciler immediately (no 15s wait).

handlers::directives `update_directive` (PR-detection branch) calls
`complete_contract(active_contract_id, pr_url, pr_branch)` instead of
`set_directive_inactive`. The contract auto-ships; the directive
follows via the sync above. No more manual "Mark complete" click.

POST /api/v1/contracts/{id}/reopen added + wired through openapi.

Spawn task names dropped the directive-title prefix that looked
redundant in the sidebar:
  "Plan: &lt;title&gt;"      → "orchestrator"
  "Re-plan: &lt;title&gt;"   → "orchestrator (re-plan)"
  "PR: &lt;title&gt;"        → "completion"
  "Update PR: &lt;title&gt;" → "completion (update)"

## Frontend — sidebar

* De-dupe: DocumentTasksFolder filters tasks[] to exclude any task
  whose id already appears in steps[].taskId. Single row per task,
  single highlight on click.
* Generic SidebarContextMenu (new) replaces the directive-only
  DirectiveContextMenu (deleted). Per-entity item arrays built at the
  page level — directive, contract, step, task each have their own
  contextual actions.
* Right-click works on every sidebar entity now (was directive-only).
* `+ New document` / `+ New ephemeral task` inline buttons removed.
  Reachable via the directive folder right-click OR the hover-only
  `+` button on the directive folder row.
* ContractHeader: dropped "Mark complete" button (auto-fires on PR).
  Added "Reopen for amendment" button when contract is shipped.

## Frontend — task page rewrite

TaskPage.tsx replaces DocumentTaskStream.tsx (deleted). Two-column
layout matches the old /exec page that the user preferred:

  ┌────────────────────────┬──────────────────────────────────┐
  │  Changed files (~30%)  │  Transcript feed (scrollable)    │
  │  ──────────────────    │  ──────────────────────          │
  │  src/foo.rs            │  [user] do thing                 │
  │  src/bar.rs            │  [tool] Read foo.rs              │
  │                        │                                  │
  │  Diff (selected file)  │                                  │
  │                        ├──────────────────────────────────┤
  │                        │  Composer (sticky bottom)        │
  └────────────────────────┴──────────────────────────────────┘

Diff comes from getTaskDiff(); parseDiff + DiffFileView exported from
OverlayDiffViewer for reuse (no duplication). Diff auto-refreshes
when the task transitions to a terminal state. Transcript styling +
sticky composer keep the parts the user liked. "Open in task page"
button removed — the right pane IS the task page.

Co-authored-by: Claude Opus 4.7 (1M context) &lt;noreply@anthropic.com&gt;</content>
</entry>
<entry>
<title>fix(directives): tasks folder visibility, circular auto-save timer, unlock-to-edit (#133)</title>
<updated>2026-05-16T17:04:17+00:00</updated>
<author>
<name>soryu</name>
<email>soryu@soryu.co</email>
</author>
<published>2026-05-16T17:04:17+00:00</published>
<link rel='alternate' type='text/html' href='http://src.eirin.xyz/soryu/commit/?id=8e2bbcab1a7b3b9005803d7ce3bfce7fa483a4d7'/>
<id>urn:sha1:8e2bbcab1a7b3b9005803d7ce3bfce7fa483a4d7</id>
<content type='text'>
* feat: soryu - makima: Fix tasks/ folder visibility and rename for multi-contract directives

* feat: soryu - makima: Replace auto-save countdown text/bar with a circular timer

* feat: soryu - makima: Require Unlock before editing a locked contract body</content>
</entry>
<entry>
<title>feat(directives): drop directives.goal — orchestration reads contract body (#132)</title>
<updated>2026-05-08T15:34:11+00:00</updated>
<author>
<name>soryu</name>
<email>soryu@soryu.co</email>
</author>
<published>2026-05-08T15:34:11+00:00</published>
<link rel='alternate' type='text/html' href='http://src.eirin.xyz/soryu/commit/?id=dce7f50e503dc374aaf879df33e725af16c4cc78'/>
<id>urn:sha1:dce7f50e503dc374aaf879df33e725af16c4cc78</id>
<content type='text'>
Hard cut. The unified contracts surface owns spec text now; the
directive itself is just a folder. The orchestrator daemon reads the
active contract's body when it spawns, replans, or runs completion.

Schema (migration 20260510000000):
  - DROP TABLE directive_goal_history
  - ALTER TABLE directives DROP COLUMN goal
  - ALTER TABLE directives DROP COLUMN goal_updated_at

New repo helper:
  - get_active_contract_body(directive_id) — picks the
    active|queued|draft contract (in that order), most-recent first.

Backend cuts:
  - Directive / DirectiveSummary / CreateDirectiveRequest /
    UpdateDirectiveRequest lose goal &amp; goalUpdatedAt.
  - CreateDirectiveRequest gains optional `contractBody` — when
    provided, create_directive_for_owner auto-creates a first contract
    with that body in the same transaction.
  - Removed: update_directive_goal, update_directive_goal_keep_orchestrator,
    save_directive_goal_history, get_directive_goal_history,
    DirectiveGoalHistory model, UpdateGoalRequest.
  - Removed handlers::directives::update_goal + the
    /directives/{id}/goal route.
  - orchestration::directive::build_planning_prompt /
    build_completion_prompt / build_order_pickup_prompt now take a
    `contract_body: &amp;str` instead of `goal_history`. classify_goal_change
    + try_interrupt_planner_with_goal_edit + GoalChangeKind +
    GoalEditInterruptResult removed (they were only useful for the
    small-vs-large goal-edit interrupt cycle).

CLI:
  - `makima directive update-goal` removed (UpdateGoalArgs deleted,
    Commands enum trimmed, ApiClient::directive_update_goal +
    UpdateGoalRequest deleted).

Frontend:
  - Directive / DirectiveSummary / CreateDirectiveRequest types lose
    goal &amp; goalUpdatedAt; CreateDirectiveRequest gains `contractBody`.
  - useDirective drops updateGoal helper.
  - api.ts updateDirectiveGoal removed.
  - Legacy DirectiveList + DirectiveDetail components deleted; the
    /directives route now always renders the document-mode page.
    The user-settings documentModeEnabled flag is no longer
    consulted at the route level.
  - NewContractModal passes body via contractBody.

Co-authored-by: Claude Opus 4.7 (1M context) &lt;noreply@anthropic.com&gt;</content>
</entry>
<entry>
<title>refactor(frontend): DocumentEditor takes explicit body/title/documentId props (#131)</title>
<updated>2026-05-08T12:43:17+00:00</updated>
<author>
<name>soryu</name>
<email>soryu@soryu.co</email>
</author>
<published>2026-05-08T12:43:17+00:00</published>
<link rel='alternate' type='text/html' href='http://src.eirin.xyz/soryu/commit/?id=e4f1622a0f0ac74707cc1c9810e0b99e948d1319'/>
<id>urn:sha1:e4f1622a0f0ac74707cc1c9810e0b99e948d1319</id>
<content type='text'>
Stops shadowing directive.goal with the contract body via a synthesised
directive object. DocumentEditor now accepts:

  * documentId — scopes the localStorage draft key per contract so
    switching contracts under the same directive doesn't clobber the
    other's unsaved edits.
  * title      — the contract title rendered as the H1.
  * body       — the contract body, used to seed the editor.
  * onUpdateBody (was onUpdateGoal)

The `directive` prop stays for orchestrator state + embedded steps
panel. document-directives.tsx drops the directiveAsDocument synthesis
hack and passes body/title from the contract directly.

This is the prep-work for dropping `directives.goal` from the schema —
once nothing reads it, the column can be dropped in a follow-up
without touching the editor.

Co-authored-by: Claude Opus 4.7 (1M context) &lt;noreply@anthropic.com&gt;</content>
</entry>
<entry>
<title>feat(contracts): drag-to-reorder active contract rows in sidebar (#130)</title>
<updated>2026-05-08T11:17:07+00:00</updated>
<author>
<name>soryu</name>
<email>soryu@soryu.co</email>
</author>
<published>2026-05-08T11:17:07+00:00</published>
<link rel='alternate' type='text/html' href='http://src.eirin.xyz/soryu/commit/?id=2dda1f96a30eee2fda86be9a8a59ce5cb26dad7f'/>
<id>urn:sha1:2dda1f96a30eee2fda86be9a8a59ce5cb26dad7f</id>
<content type='text'>
HTML5 drag/drop on active contract rows. Dragging a row over
another in the same directive folder shows a green top-border drop
indicator; dropping calls reorderDirectiveContract(id, targetPosition)
and refreshes the folder. Shipped/archived rows aren't draggable
(historical, ordering is fixed).

Implementation:
- DocumentRow gains optional draggable + drag event props.
- DirectiveFolder owns the drag/over state and handleReorder
  callback; computes target position from the drop-target row's
  current position.
- Repository's reorder endpoint already exists from the backbone PR
  and handles sibling shift in a transaction.

Co-authored-by: Claude Opus 4.7 (1M context) &lt;noreply@anthropic.com&gt;</content>
</entry>
<entry>
<title>feat(contracts): lifecycle — Lock/Start/Pause/Complete/Unlock + queue scheduler (#129)</title>
<updated>2026-05-08T11:12:51+00:00</updated>
<author>
<name>soryu</name>
<email>soryu@soryu.co</email>
</author>
<published>2026-05-08T11:12:51+00:00</published>
<link rel='alternate' type='text/html' href='http://src.eirin.xyz/soryu/commit/?id=6690b714c64aaef5781bc0aac41b777ab72e9070'/>
<id>urn:sha1:6690b714c64aaef5781bc0aac41b777ab72e9070</id>
<content type='text'>
Adds the contract lifecycle layer on top of the unified-contracts
backbone (#128). State machine:

    draft → queued → active → shipped → archived

At most one contract per directive sits in `active` at any time —
the queue is serialised because each directive owns a single shared
worktree. Repository helpers handle the transition checks AND
auto-promote the next-up `queued` contract whenever the active slot
frees (pause / complete / unlock-from-active / archive-from-active).

Endpoints (all under /api/v1/contracts/{id}):
  POST /start    draft → queued | active (depending on slot)
  POST /pause    active → queued; promotes next queued
  POST /complete active → shipped; optional pr_url + pr_branch
  POST /unlock   queued | active → draft; promotes if was active

Frontend wiring:
  * `DirectiveContractStatus` now includes `queued`.
  * Migration adds `queued` to the CHECK constraint on
    directive_documents.status.
  * `ContractHeader` component renders breadcrumb + status pill +
    status-driven action buttons + a merge-mode (shared / own_pr)
    radio. Merge mode is editable only while draft / queued so a
    running flow's branch target can't change mid-stream.
  * RepositoryError gains a `Validation(String)` arm; the three
    existing exhaustive matches (files, mesh, versions) get a
    400 BAD_REQUEST response for it.

Drag-to-reorder UI deferred to a small follow-up — the backend
endpoint already exists from the backbone PR.

Co-authored-by: Claude Opus 4.7 (1M context) &lt;noreply@anthropic.com&gt;</content>
</entry>
<entry>
<title>feat(directives): unified contracts surface — backbone (#128)</title>
<updated>2026-05-08T10:29:56+00:00</updated>
<author>
<name>soryu</name>
<email>soryu@soryu.co</email>
</author>
<published>2026-05-08T10:29:56+00:00</published>
<link rel='alternate' type='text/html' href='http://src.eirin.xyz/soryu/commit/?id=e00be74c8b575c725829677aadeb755ee81454d0'/>
<id>urn:sha1:e00be74c8b575c725829677aadeb755ee81454d0</id>
<content type='text'>
This is the backbone PR for the unified directive workflow. A directive
holds a sequence of contracts; each contract is a spec body whose
execution drives tasks in the directive's shared worktree. Lifecycle
(Lock &amp; Start, queue scheduler, drag-reorder) lands in follow-ups.

What's in this PR:
- Migration adds `position` (queue order) and `merge_mode`
  (shared|own_pr) columns to directive_documents. The actual table
  rename is deferred — the legacy `contracts` table from the old
  contracts system still exists, and the rename collision waits for
  Phase 5 to drop legacy contracts.
- Repository: list orders by position; create assigns next-position;
  update accepts merge_mode; new reorder_directive_document_position
  shifts siblings inside a transaction.
- HTTP: endpoints aliased under /api/v1/directives/{id}/contracts and
  /api/v1/contracts/{id}/... with a new /contracts/{id}/reorder.
- Frontend: api types renamed `DirectiveContract*` (avoiding the
  legacy `Contract` type collision); document-directives.tsx imports
  via aliases so the rest of the file is untouched.

Internal struct + table names stay `DirectiveDocument` /
`directive_documents` until the legacy contracts cleanup.

Co-authored-by: Claude Opus 4.7 (1M context) &lt;noreply@anthropic.com&gt;</content>
</entry>
<entry>
<title>fix(doc-mode): make task rows clickable and render live transcript (#125)</title>
<updated>2026-05-05T15:30:46+00:00</updated>
<author>
<name>soryu</name>
<email>soryu@soryu.co</email>
</author>
<published>2026-05-05T15:30:46+00:00</published>
<link rel='alternate' type='text/html' href='http://src.eirin.xyz/soryu/commit/?id=928598b1b8399a95918dc1b315274a9d175eb8d9'/>
<id>urn:sha1:928598b1b8399a95918dc1b315274a9d175eb8d9</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>
</feed>
