Files
stack/docs/plans/2026-10-18_row128-thread-cli.md
jason.woltjeandClaude Opus 5.5 0f3eb25ea0 plans: refreshed row 128 brief, the bus project and thread verbs and talk --thread (#1622)
The 2026-10-14 brief predates rows 121, 142 and 143. This one names the
verbs on the existing broker ops, keeps plain talk asking for a thread
with no default, and targets acceptance 314 steps 1 and 3. Owner moves
to researcher.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-18 09:03:57 -05:00

6.6 KiB

Row 128 brief, refreshed 2026-10-18

This replaces the short brief in docs/plans/2026-10-14_prd-1.2-build.md ("mosaic talks to the assistant in a named thread"). Rows 121, 142 and 143 have landed since that brief was written, so the bus side is done and the CLI side can be named exactly. Line numbers are at ac55e84fe.

mosaic talks to the assistant in a named thread

Problem

The bus has every project and thread op since row 121 (#1615): project.create and project.list (packages/bus/src/broker.mjs:2050, :2068), thread.create, thread.list, thread.open, thread.send and thread.messages (:2074, :2098, :2112, :2119, :2146). No code in packages/cli or packages/webui calls any of them. The assistant is the business's threaded instance, and the broker refuses a human's plain message.send to it with thread-required-use-thread-send (broker.mjs:288). So today Jason can't create a project or a thread, and mosaic talk assistant ... can only fail. Acceptance run 314 (docs/acceptance/314.md) needs both: step 1 creates a bus project, an assistant thread in it and opens it, and step 3 talks in that thread and expects only the assistant's reply. Requirements: REQ-CLI-1, REQ-CLI-2, REQ-THREAD-2, REQ-USER-2 (docs/prd/mosaic-stack.md:475, :668, :673). Gitea #1622.

Owner and reviewer

  • Owner: researcher.
  • Reviewer: filbert (CLI only, no broker or sandbox change).

Files owned

  • packages/cli/src/cli.mjs (dispatch, USAGE, talk and follow)
  • packages/cli/src/project.mjs (the create and list subcommands)
  • packages/cli/src/thread.mjs (new: thread verbs and the thread resolver)
  • packages/cli/tests/thread-cli.test.mjs (new)
  • packages/cli/tests/project.test.mjs
  • packages/cli/tests/follow.test.mjs, only if the follow loop's existing tests need a thread case
  • packages/cli/README.md, docs/TOOLS.md
  • docs/acceptance/314.md, steps 1 and 3 only: replace "row 128's commands" with the real command lines
  • the packet agents/researcher/work/queue-128/

No change to packages/bus. If a verb below can't be built on the existing ops, stop and tell Sage; that is a brief change, not a fix in scope.

What ships

Verbs. Every one goes through callFor (cli.mjs:172), so the human transport, --business and the refusal inside an agent work as they do for talk today. Each list verb takes --json.

  1. mosaic project create <name> [--repo <repo>] calls project.create. mosaic project list calls project.list and prints name, repo and a short id. They join init and check under the project verb. init and check keep their exact arguments and refusals; create and list work on the bus record, init and check on the repository on disk, and docs/TOOLS.md says that in one sentence.
  2. mosaic threads [--project <project>] calls thread.list and prints project name, thread name, instance and a short id.
  3. mosaic thread create <project> <name> calls thread.create and prints the id and the instance. mosaic thread open <thread> calls thread.open. mosaic thread read <thread> pages thread.messages and prints the history oldest first; it marks nothing read.
  4. mosaic talk --thread <thread> <text> [--wait <s> | --follow] sends with thread.send, class REQUEST, and takes one positional. Without --follow it prints only the message whose in_reply_to is the sent id, as row 142 does for roles (cli.mjs:348), and leaves the rest unread. With --follow it prints every message in that thread after the sent one and marks read those addressed to the human; messages of other threads and outside threads stay unread for mosaic inbox. mosaic follow --thread <thread> is the same loop without the send.
  5. Plain mosaic talk <role> <text> to a threaded instance asks for a thread; there is no default thread. On thread-required-use-thread-send the CLI exits 2 with a message that names --thread and mosaic threads. The bus never picks between instances, and a CLI default would pick between Jason's threads for him. The packet records this choice.

Thread and project references. A project is its name or its id. A thread is its id, an id prefix of at least 8 characters, or <project>/<name>. The resolver reads project.list and thread.list and refuses an unknown or ambiguous reference before any send, the way findDecision does (cli.mjs:111).

Refusals. thread-not-owned, thread-not-found, project-not-found, project-exists, thread-exists, unknown-repo, thread-instance-missing and thread-instance-ambiguous each print one plain line and exit non-zero. The CLI adds no check the broker already makes.

Tests, in packages/cli/tests/thread-cli.test.mjs against a real broker the way thread-launch.test.mjs builds one:

  • project create and list, including project-exists and unknown-repo; init and check arity refusals unchanged;
  • thread create, list (with and without --project), open and read;
  • the resolver: id, prefix, <project>/<name>, too-short prefix, unknown and ambiguous;
  • talk --thread prints only the reply to the sent id and leaves an unrelated message unread; --wait timeout; --follow prints only that thread's messages and leaves another thread's message unread;
  • plain talk to the assistant gets the --thread message, exit 2;
  • REQ-USER-2: a thread owned by another human. talk --thread, thread open and thread read on it are refused with thread-not-owned, and no message, open or delivery row is written.

Mutants: one per behavior above, recorded in the packet with the killing test, as row 142's packet does.

Suites: node --test packages/cli/tests/*.test.mjs, then the full gate.

Acceptance 314: after this row, step 1's bus half is mosaic project create stack --repo stack, mosaic thread create stack assistant, mosaic thread open stack/assistant and mosaic threads --project stack; step 3 is mosaic talk --thread stack/assistant "<text>". The builder writes the real lines into docs/acceptance/314.md.

Out of scope

  • Renaming a project or a thread: no broker op exists. P19 follow-up.
  • The Console chat area: row 129 (#1623).
  • Closing, deleting or archiving threads.
  • Any broker, schema or launcher change.
  • A live smoke. Steps 1 and 3 run in Jason's acceptance run, after the re-pin and with Mos's go.

Gate

Filbert approves on #1622, naming the candidate manifest digest. Sage reruns the full gate at the landing target, and it must be green (scripts/test-*.sh plus the package suites, 25 of 25 as on 6e7fdf7ff). The REQ-USER-2 test above passes and its mutant is killed.