DUNIN7 · LOOMWORKS · RECORD
record.dunin7.com
Status Current
Path change-requests/composer-placement-and-message-order-change-request-v0_1.md

Composer placement and message order change-request

Version. 0.1 Date. 2026-05-19 Author. Claude.ai (this conversation) Working machine. The Mac Mini, with Claude Code as the executor Repository. DUNIN7/loomworks (Operator Layer frontend, primary) and DUNIN7/loomworks-engine (substrate, optional small addition for the new preference key) Substrate baseline. loomworks-engine main at tag engagement-list-scoping-v0_1 (commit 37dd842) — current head. Frontend baseline. loomworks build branch phase-60-operator-layer-upload-pathway-v1 at tag engagement-list-scoping-v0_1 (commit f26531f) — current head. Grounded in.


Plain-language summary

This change-request changes the composer placement and message order on the in-engagement surface. The current shape (composer at bottom, conversation oldest-at-top, fixed-height composer that shows a scrollbar when content overflows) is the chat-app convention. The new shape (composer at top, conversation newest-at-top, composer that auto-expands with content) matches the rest of Loomworks (Inbox, Library, engagement-navigation are all newest-first) and supports the thinking surface product identity.

The change is made per-Operator-settable: the default is the new Loomworks-native shape (top composer + newest-first), and Operators who prefer the chat-app convention can flip the setting once. The setting lives in person_settings; the Operator changes it by saying "show newest first" or "show oldest first" to the Companion, matching the Companion-tunable-settings pattern.

What lands.

What you (the Operator) see after this ships.

Open any engagement. The composer is at the top of the conversation card. The most recent turn is right below the composer. Older turns flow downward; scrolling down reveals older conversation. New turns (sent by you, replied by the Companion) appear immediately below the composer, pushing previous turns down.

Type a long message — the composer grows vertically as you type, instead of showing a tiny scrollbar.

Say "show oldest first" to the Companion — the conversation re-renders with the chat-app convention (composer at the bottom, conversation oldest-at-top, latest turn just above the composer). Say "show newest first" to switch back.

What this change-request does not do.

Estimated effort. Two checkpoints — Substrate addition is small (one new setting key, recognized by the existing tune_setting handler); frontend work is the larger piece (CenterPane composition reshape plus composer auto-expand).

Methodology inheritance. Thinking-surface-not-messaging-surface is the load-bearing principle this ship serves. Loomworks-pattern-over-imported-convention justifies the newest-first default. Companion-tunable-settings-as-Companion-said-not-menu-clicked governs the setting's surface. Build-the-skeleton-first doesn't apply (the layout exists; this is a reshape, not a new layout) and mockup-as-build-target is honored against the v0.6 register though not against the v0.2 layout reference's composer-at-bottom (which is acknowledged as a v0.2 default that this change-request deliberately supersedes per Loomworks-pattern-over-imported-convention).


Step 0 — Codebase inspection block

Step 0.1 — Pre-flight


ls -la /Users/dunin7/loomworks-engine
ls -la /Users/dunin7/loomworks
cd /Users/dunin7/loomworks-engine && git status
cd /Users/dunin7/loomworks && git status
git -C /Users/dunin7/loomworks-engine log --oneline -3
git -C /Users/dunin7/loomworks log --oneline -3

Both working trees clean. Both at engagement-list-scoping-v0_1 or later.

Step 0.2 — Existing tune_setting handler

Confirm the handler's current shape and the recognized setting keys:


cd /Users/dunin7/loomworks-engine
grep -n "tune_setting\|blur_intensity\|voice.listening" src/loomworks/orchestration/save_filter.py src/loomworks/orchestration/router.py 2>/dev/null
ls -la src/loomworks/orchestration/tune_setting.py 2>/dev/null

Report the handler file path and the existing parser shape. The voice blur intensity ship landed the handler; this change-request extends the same handler's vocabulary to recognize message-order phrasings.

Step 0.3 — Existing person_settings primitives


ls -la src/loomworks/preferences/person_settings.py
grep -n "GET /me/settings\|PUT /me/settings" src/loomworks/api/routers/

The table, the read/write module, and the request/response endpoints are all in place from the voice ship. No new substrate primitive needed.

Step 0.4 — Frontend CenterPane current shape


cd /Users/dunin7/loomworks
cat src/app/operator/engagement/\[engagement_address\]/CenterPane.tsx | head -100

Confirm the current composition. The composer is mounted at the bottom of the center area; the conversation flows above it; auto-scroll keeps the latest turn visible at the bottom edge. This change-request reshapes both.

Step 0.5 — Existing me-settings adapter


ls -la src/lib/api/me-settings.ts
grep -n "fetchMeSetting\|putMeSetting" src/lib/api/me-settings.ts

The generic settings adapter is in place from the voice ship. The new key conversation.message_order reads through the same adapter; no new adapter needed.

Step 0.6 — Halt-or-proceed

If any check surfaces drift, halt and report. If everything matches, proceed to Section A.


Section A — Substrate extension

A.1 — tune_setting vocabulary extension

The existing tune_setting handler (from the voice ship) recognizes blur-intensity phrasings. This change-request extends its parser to recognize message-order phrasings.

New recognized phrases:

The handler's existing structure (extract setting + extract value, validate, write, responder confirms with new value in plain words) applies as-is. The responder's reply names the setting and the new order in plain language ("Showing newest messages first. The conversation will reload with the new order on next render.").

A.2 — Default value

The substrate default for conversation.message_order is "newest_first". Operators with no row in person_settings for this key receive the default when the frontend queries.

A.3 — Tests

Per-phrasing tests for the parser plus cascade tests for the handler:

Approximately six to eight new pytest tests. All existing substrate tests continue to pass.


Section B — Companion handler

The handler is the existing tune_setting handler from the voice ship, extended in Section A. No new handler file. The save_filter handler from Phase two stays unchanged.


Section C — Frontend conversation reshape

The single deliverable. CenterPane reshapes to top-composer / newest-first by default, with the setting controlling order.

C.1 — Read the setting on mount

CenterPane (or its parent composition root) reads conversation.message_order via fetchMeSetting<string>("conversation.message_order") on mount. The returned value (or default "newest_first") drives the render order.

C.2 — Layout reshape: composer at top, conversation below

When message_order === "newest_first":

When message_order === "oldest_first":

The activity ribbon stays in the conversation header in both modes — its position is independent of the composer/conversation order.

C.3 — Composer auto-expand

The composer's text area uses field-sizing: content (modern CSS) or a JavaScript-based auto-resize (height adjusted to scrollHeight on input) to grow vertically with the content.

Minimum height: one line (current default). Maximum height: roughly 12 lines of text (after which a scrollbar appears inside the composer). The exact maximum is a token-faithful render in the v0.6 register; Claude Code's call at execution.

When the composer grows, the conversation area below (newest-first mode) or above (oldest-first mode) shifts to accommodate. The total center pane height is fixed by the viewport; the conversation area's height adjusts as the composer expands.

C.4 — Setting re-read on page render

The setting is read on CenterPane mount. If the Operator changes the setting via the Companion mid-session, the conversation re-renders with the new order on the next render (page navigation or refresh). This matches the voice blur-intensity behavior (re-read on each listening-panel open) — same shape, same constraint.

Future direction: server-sent events for live preference updates would let the order change immediately without a refresh. Out of scope at v0.1.

C.5 — Tests

Vitest unit tests cover:

Approximately ten to fifteen new tests. All existing vitest tests continue to pass — especially the conversation history fetch and the composer-send pathway.

C.6 — Removed: composer-scroll-into-view fix

The composer-scroll-into-view fix (from the voice routing work earlier) was conditional on the composer being at the bottom of the page. With the composer at the top (newest-first mode, default), the scroll-into-view is no longer needed for that mode — the composer is already at the top of the viewport. In oldest-first mode, the scroll-into-view continues to apply.

Claude Code's call at execution: either gate the scroll-into-view to oldest-first mode only, or remove the fix entirely if the chat-surface composer-prefill case is no longer reachable post-engagement-list-scoping.


Section D — Verification

Checkpoint A — substrate vocabulary extension.


cd /Users/dunin7/loomworks-engine
pytest tests/test_tune_setting*.py -v
pytest

New handler tests pass; full suite shows no regressions. Halt for Operator review before Section C.

Checkpoint C — frontend reshape.


cd /Users/dunin7/loomworks
npm test
npm run build

All existing vitest tests plus the new tests pass. Build succeeds.

Smoke test.

  1. Open /operator/engagement/<an engagement with conversation history> (E0005 Loomworks works — has the Hello + API + voice turns from earlier sessions).
  2. Confirm: composer is at the top of the conversation card. Most recent turn (the API-key reply from the latest voice test) is right below the composer. Older turns flow downward.
  3. Type a long message into the composer — confirm it expands vertically as you type.
  4. Send the message — confirm the new Operator turn appears immediately below the composer, the Companion's reply appears below the Operator turn (or above the previous most-recent turn — either ordering is valid; Claude Code's call at execution depends on substrate timing).
  5. Say "show oldest first" to the Companion via voice or text.
  6. Refresh the page. Confirm the conversation now renders chat-app convention (composer at bottom, conversation oldest-at-top).
  7. Say "show newest first" — refresh — back to Loomworks default.

Halt for Operator visual confirmation.


Section E — Acceptance criteria

  1. Default render: composer at top, conversation newest-first below it.
  2. Composer auto-expands with content up to a sensible maximum.
  3. The setting conversation.message_order is read on CenterPane mount.
  4. The Companion's tune_setting handler recognizes the new message-order phrasings.
  5. Saying "show oldest first" writes the setting; next render shows chat-app convention.
  6. Saying "show newest first" writes the setting; next render shows Loomworks default.
  7. New turns appear in the correct position per mode (immediately below composer in newest-first; immediately above composer in oldest-first).
  8. All existing tests continue to pass; new tests cover the reshape and the setting.
  9. The Operator confirms by eye that the reshape feels right for the thinking-surface use rhythm.

Section F — Out of scope


Section G — Methodology inheritance

G.1 — Thinking-surface-not-messaging-surface

Honored. The whole change-request implements the principle. The composer-at-top placement treats the composer as the active workspace (per the principle's claim about thinking-surface composers). Newest-first ordering treats conversation as reference material accessed by recency rather than as transcript read start-to-finish.

G.2 — Loomworks-pattern-over-imported-convention

Honored. The newest-first default matches Inbox, Library, and engagement-navigation throughout the rest of Loomworks. The chat-app convention is preserved as an opt-in setting for Operators who prefer it, but it's no longer the default.

G.3 — Companion-tunable-settings-as-Companion-said-not-menu-clicked

Honored. The setting is changed by saying it to the Companion. No menu surface is added. The tune_setting handler's vocabulary extends to handle the new phrasings.

G.4 — Build-the-skeleton-first

Not applicable. The layout exists; this is a reshape, not a new layout.

G.5 — Mockup-as-build-target

The v0.6 visual register is honored. The v0.2 layout reference's composer-at-bottom is deliberately superseded per G.2 — the v0.2 layout predates the v0.6 register and predates the thinking-surface principle; deferring to it would import the chat-app convention this principle rejects.

G.6 — Context-shapes-affordance

Adjacent. The composer is the same component in both modes; only its placement and the conversation order around it differ. This is the principle in another instance.


Operator approval


Approved for execution.
- Marvin Percival
- [timestamp]

Once approval is recorded, Claude Code executes end-to-end, halting at Checkpoint A and Checkpoint C.


Document trailer

DUNIN7 — Done In Seven LLC — Miami, Florida Composer placement and message order change-request — v0.1 — 2026-05-19 Grounded in loomworks-stream1-engagement-navigation-mockup-v0_6_1.html (visual register), loomworks-operator-layer-mockup-v0_2.html (layout reference, deliberately superseded for the composer placement), and the methodology candidates from 2026-05-19 (thinking-surface-not-messaging-surface, Loomworks-pattern-over-imported-convention, Companion-tunable-settings-as-Companion-said-not-menu-clicked) Builds on engagement-list-scoping-v0_1 (current head) Next ships after this: composer auto-expand polish (already in this ship), workspace breadcrumb on in-engagement surface, voice listening timeout reset, sign-in back-then-paste resolution. Requires Operator approval before Claude Code begins execution.