---
title: "Seamstresses — long work now leaves the loom without leaving your sight"
description: "What changed, in one paragraph: the loom has a third kind of worker. Alongside the Designer (who talks with you) and the Tailor (who runs the room), there are now Seamstresses — named agents who take long, settled work…"
created: 2026-09-16
updated: 2026-09-21
authors: ThinkingCap R&D
topics: [Tapestry]
status: published
canonical: https://console.thinkingcap.com/rd/Tapestry/Loom-Seamstresses
date: 2026-09-16
---

# Seamstresses — long work now leaves the loom without leaving your sight

**What changed, in one paragraph:** the loom has a third kind of worker. Alongside
the Designer (who talks with you) and the Tailor (who runs the room), there are now
**Seamstresses** — named agents who take *long, settled work* away and build it
autonomously while you change focus to something else. A new **WORKBENCH** tab in
every loom is where you watch them: up to three chairs, each with a name, a focus,
and a live transcript you can open with one click.

---

## Using it (the short version)

- **The Designer creates them — you never do.** No button, deliberately: when the
  conversation has produced settled long work, the Designer dispatches a Seamstress
  with a complete written work order. The conversation is what makes the work order
  good; a button would bypass it.
- **She pulls her own name** from a pool of common 19th-century English names —
  Penelope, Beatrice, Alice. The name is how you refer to the work: *"what's
  Penelope doing?"*
- **She never interrupts you.** When she's stuck or finished she tells the
  *Designer*, who relays it in the loom in her own words at a natural moment:
  *"Penelope is asking whether the sampler dedupes by learner or by course — would
  you like to pause what we're doing and ask her back in?"* Your answer travels back
  the same way, or you type it straight into her Workbench reply box.
- **The WORKBENCH tab** (scissors icon, next to FLAX): three chairs with name,
  status, focus, live progress, elapsed time. Click for her full transcript.
  Reply / Pause / Resume / Recall are your controls. Finished Seamstresses sit
  "off the bench" below with their outcomes.
- **Three chairs per loom, max.** A fourth dispatch is refused with the names of
  who's working.
- **She never pushes.** She commits checkpoints on her own branch
  (`seamstress/penelope-a1b2`); review the diff, push when satisfied. Nothing an
  agent writes ever reaches a real repo on its own.

---

## Under the hood

### The moving parts

| Piece | Where | What it is |
|---|---|---|
| Agent loop | `src/workers/seamstress.ts` | Polls the `seamstresses` table every 5s, runs up to 3 concurrent Seamstresses. Each "segment" is up to 80 LLM rounds (Sonnet, tool-use loop), then she pauses for breath. |
| Data plane | `src/services/seamstresses.ts` | The `seamstresses` Postgres table, dialog, expert roster, the Designer's garment block. |
| Room relay | `src/services/seamstressRelay.ts` | Her ONLY channel to the room. Writes relay rows to the Fabric and wakes the Designer (debounced) when the loom is quiet. |
| Designer tools | `src/lib/worktreeTools.ts` | `wt_dispatch_seamstress` / `wt_message_seamstress` / `wt_recall_seamstress` — the Designer's entire seamstress surface, on the existing worktree tool surface. |
| REST | `src/routes/seamstresses.ts` | List / transcript / reply / pause / resume / cancel for the Workbench. No dispatch endpoint (see above). |
| UI | `frontend/src/components/main/content/WorkbenchPanel.tsx` + mode wiring | The tab: 5s poll while anyone's active (15s idle), plus `seamstress_event` ws pushes. |

### How her work shows in the Fabric

Everything a Seamstress does is ordinary Fabric — `conversation_messages` rows,
same as every other loom record — but **in her own conversation**, not the loom's
main one. At dispatch she gets a `conversations` row of her own
(`execution_mode='seamstress'`), which keeps her hundreds of working rows out of
the main chat and Fabric views while remaining fully queryable. The Workbench's
transcript view is simply that conversation read back in order.

Her rows carry distinct `message_type`s so projections can tell them apart:

| message_type | What it is |
|---|---|
| `seamstress_dispatch` | The work order, as row one of her transcript. |
| `seamstress` | Her own narration — what she's doing and why, in the Weaver's terms. This is also the source of the one-line "progress" on her Workbench card. |
| `seamstress_tool` | One compact line per tool call (`sm_edit_file(src/x.ts) → Edited (2 anchors)…`) — the story stays readable without dumping file contents. |
| `seamstress_expert` | An expert's answer to her direct consult (metadata carries the advisor's name). |
| `seamstress_dialog` | Answers from the room (Weaver or Designer) as they arrive. |
| `seamstress_done` / `seamstress_cancelled` | Terminal markers with her summary / recall reason. |

The loom's **main** conversation gets exactly one new row type:
**`seamstress_relay`** — her reports, addressed to the Designer and marked
("…her report to the Designer, not the Weaver speaking"). That's the only thing
of hers that ever touches the room's Fabric. (The message_type allow-list is a
CHECK constraint on `conversation_messages`; the migration in
`scripts/seamstresses.sql` extends it.)

### The relay — how she "never interrupts"

Her report path is mechanical, not polite-by-prompt:

1. Worker writes a `seamstress_relay` row into the loom's conversation (question,
   done, breath-pause, failed, recalled — with kind + her id in metadata).
2. **If the loom is streaming, nothing else happens yet** — the row waits in the
   Fabric; a 15s debounced re-check fires only when the loom goes quiet (10-min
   cap; after that the next natural turn carries it anyway). Multiple reports
   while busy collapse into one wake.
3. When quiet, the relay calls `startStream()` with a fixed "workbench bell"
   instruction (committed as another `seamstress_relay` row). The Designer reads
   all waiting relay rows in her garment and relays each to the Weaver **in her
   own words** — that's the "would you like to pause what we're doing and ask her
   back in?" moment.
4. The Designer's system prompt carries a **Seamstress block** (built per-turn by
   `buildSeamstressBlock()`): who's at the bench, their status, and the protocol
   — relay in your own words, carry answers back with `wt_message_seamstress`,
   never answer *for* the Weaver unless it's already settled in the Fabric.

Answers come back through `wt_message_seamstress` (Designer) or the Workbench
reply box (Weaver): appended to her `dialog` jsonb, written into her transcript,
and if she was paused she flips back to `pending` — the worker resumes her with
the answer folded into context.

### The agent loop, concretely

- **Claiming**: `UPDATE … WHERE id IN (SELECT … WHERE status='pending' … FOR
  UPDATE SKIP LOCKED)` — oldest first, max 3 running, single-process worker.
- **Segment**: restore `harness_state` (her Anthropic message array + token
  totals) → up to 80 rounds of `messages.create` with her `sm_*` tools → persist
  text to her transcript as it lands → tool results back in. Every 5 rounds the
  harness is saved; old tool results are elided before saving (files are on
  disk — she can re-read them), so pause/resume and process restarts are exact.
- **Pause/resume**: `pause_requested` is checked every round; she saves state and
  holds. A cancel sets an in-memory kill signal plus a DB status — both checked
  per round and per tool call.
- **Breath**: 80 rounds without `sm_done` → checkpoint commit, save, pause with a
  note to the room. A runaway can't run away.
- **Zombie net**: on worker start, `running` rows idle 45m+ are force-failed with
  a relay to the room. Her shop and branch survive everything, always.

### Her tools and the gates

Her surface is `sm_*` (read/list/write/edit/delete, run_command, git_status,
git_diff, commit, ask_expert, ask, done) — a sibling of the Designer's `wt_*`
worktree surface with the same three gates:

1. **Blast radius** — every path contained to her shop (`lib/pathContainment`).
2. **Git is the Weaver's** — she can `sm_commit` checkpoints on her own branch;
   no push tool exists.
3. **No infrastructure** — `sm_run_command` shares the worktree whitelist
   (npm/dotnet builds and tests, read-only git).

**Deterministic helpers get first claim.** `sm_run_command` routes through
`routeViaHelper()` — the same agent-ops helper router the Designer uses — before
local execution: a live helper's stdout *is* the tool result, exit 42 falls
through to her shop, a helper failure is the tool error. As the helper registry
graduates more families, her calls are absorbed with no seamstress change. The
gates are absolute, though: a whitelist-*refused* command gets no helper path —
a push helper would break Gate 2, a VM helper Gate 1. Her other tools are
deterministic by construction (fixed git/fs argv; the agent supplies only text).

### Expert consults

At dispatch, her roster is frozen from the loom's Fabric: every advisor with an
`expert_voice` row in the conversation that led to her work (cap 6, stored on her
row as `experts jsonb`). `sm_ask_expert(name, question)` fires a one-shot haiku
call in that expert's persona (same model and voice style as the loom's expert
rounds), writes the exchange to her transcript as a `seamstress_expert` row, and
returns the answer as the tool result — she never pauses for it. Experts are for
domain questions; scope and priorities still go to the room via `sm_ask`.

### The table

```sql
seamstresses (
  id uuid PK, loom_id text → looms, name text,
  status text CHECK (pending|running|paused|success|failed|cancelled),
  focus_subject text, spec text,
  repos jsonb,            -- [{full_name, friendly_name}] (0–2)
  experts jsonb,          -- roster frozen at dispatch
  conversation_id uuid → conversations,   -- her transcript
  dispatched_by text,     -- 'designer' (only path)
  progress text,          -- one-liner feeding the Workbench card
  dialog jsonb,           -- Q&A with the room
  harness_state jsonb,    -- agent-loop state for exact resume
  result text, error text, pause_requested bool,
  created_at / started_at / updated_at / completed_at
)
```

### Ops notes

- Worker starts with the service (`[seamstress] started — polling every 5s, 3
  chairs at the Workbench`); `DISABLE_SEAMSTRESS=true` keeps it off a host.
  Needs no Azure — Postgres, Anthropic, git only (deliberately NOT under the
  dresser's az-CLI gate).
- Live on tapestry.team (branch `seamstresses`, latest deploy 9d9c453).
  Migration: `scripts/seamstresses.sql` (table + constraint extension) — already
  applied to the platform DB.
- Cost shape: Sonnet for the work loop, haiku for expert consults; 80-round
  segments and 3-concurrent caps bound the blast radius; per-run token totals
  land in her completion summary.

*Questions to Douglas — or ask the Designer in your loom; she knows the protocol.*
