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.
loomworks-stream1-engagement-navigation-mockup-v0_6_1.html — visual register and v0.6 register continuity.loomworks-operator-layer-mockup-v0_2.html — layout reference for the in-engagement surface (the prior composer-at-bottom shape, which this change-request supersedes).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.
conversation.message_order (values: "newest_first" or "oldest_first"; default "newest_first") lives in person_settings.tune_setting handler is extended to recognize "show newest first", "show oldest first", "reverse order", "flip the conversation" and write the setting.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.
/chat redirect or any prior route behavior.
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).
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.
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.
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.
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.
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.
If any check surfaces drift, halt and report. If everything matches, proceed to Section A.
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:
conversation.message_order to "newest_first".conversation.message_order to "oldest_first".conversation.message_order to "newest_first" (the substrate default).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.").
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.
Per-phrasing tests for the parser plus cascade tests for the handler:
"newest_first"."oldest_first"."newest_first" if currently oldest, "oldest_first" if currently newest."newest_first").Approximately six to eight new pytest tests. All existing substrate tests continue to pass.
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.
The single deliverable. CenterPane reshapes to top-composer / newest-first by default, with the setting controlling order.
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.
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.
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.
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.
Vitest unit tests cover:
conversation.message_order on mount."newest_first".Approximately ten to fifteen new tests. All existing vitest tests continue to pass — especially the conversation history fetch and the composer-send pathway.
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.
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.
/operator/engagement/<an engagement with conversation history> (E0005 Loomworks works — has the Hello + API + voice turns from earlier sessions).Halt for Operator visual confirmation.
conversation.message_order is read on CenterPane mount.tune_setting handler recognizes the new message-order phrasings./chat) composer. Redirected away from in the in-engagement fill-in ship; the existing ChatView component continues to exist with its bottom-composer shape but isn't a surfaced route.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.
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.
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.
Not applicable. The layout exists; this is a reshape, not a new layout.
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.
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.
Approved for execution.
- Marvin Percival
- [timestamp]
Once approval is recorded, Claude Code executes end-to-end, halting at Checkpoint A and Checkpoint C.
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.