Skip to content

feat(app): Claude's question card takes screenshots with its answer - #188

Open
Stener1 wants to merge 2 commits into
cosscom:mainfrom
Stener1:question-card-images
Open

Stener1 wants to merge 2 commits into
cosscom:mainfrom
Stener1:question-card-images

Conversation

@Stener1

@Stener1 Stener1 commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Claude's question card takes screenshots. Paste one into a question's Something else…, or drop files on the card, and they go with the answer for Claude to look at. Files already in the reply box, or dropped there while the question waits, move to the card. They leave the reply box once the answer goes, so they aren't sent again.

 <ConversationPane>
+  <ChatFiles target={box, session}>      # one useAttachments, shared; progress redraws only its readers
     <QuestionsContext>
       <QuestionCard> → <Form>
+        take() while drawn                # the reply box hands it its files
+        owner: file → question on screen   # kept per question tool
+        chips · paste into own words · drop on card · Submit waits for the files it sends
     <ChatFoot> → <Reply>
-      useAttachments(attach)
+      useChatFiles()                      # chips hidden while a form takes them

An answer stays one line of text. No box API change.

this one is off [attached: /…/My Projects/shop/.berth/attachments/…-checkout-step-2.png, /…/pasted-163707.png]

Paths are parted by , and the next path's /, so a path with a space stays one. Not quotes: on Claude's SDK the box reads the answer back from Claude's "question"="answer" result text, which doesn't escape quotes inside an answer.

attachedTo / splitAttached sit next to withAttachments in lib/attachments.ts. The answered card shows the files by name (📎 checkout-step-2.png, pasted-…png), not by path, without the box's time and same-second count (20261025-152924-1-shot.png → shot.png).

Box, terminal driver: Claude Code breaks a path that is longer than a line inside it (…/acme-shop/.b ⏎ erth/attachments/…). The screen check used to join wrapped lines with a space, so in an 80x24 pane the answer stuck. Now answer.go treats a line break as either a space or nothing, and only there; a space anywhere else still counts.

Verify skill: features/attachments.md is new (the composer and the card). features/chat-questions.md gets the card case. New scenarios chat-question-images (mock) and chat-question-images-live (real box, either driver). dev-box.sh gets two fixes:

  • The caller's BERTH_* no longer reaches the box's agents. Started from a structured worker, BERTH_DRIVER=structured turned their hooks off.
  • It waits for Claude's trust question or its prompt (up to 90 s), answers the question once, and stops with Claude's screen when neither shows. A folder already trusted no longer gets Up+Enter, which re-sent the last prompt.
  • env quotes a box dir with a space (VERIFY_BOX_DIR='/tmp/verify berthd').

Evidence

After the rebase onto main and the review fixes (head 2ef40c56): chat-question-images-live on a dev box built from this branch, with VERIFY_BOX_DIR='/tmp/vb 2541', so every attached path has a space in it. The dropped file is named checkout step 2.png (the box makes it checkout-step-2.png). Both drivers pass, with no console errors. The scenario now also checks the answer again after Claude's record replaces the one sent.

  • Terminal driver, pane at 80x24. Transcript answer: this one is off [attached: /tmp/vb 2541/acme-shop/.berth/attachments/20261027-134208-checkout-step-2.png, /tmp/vb 2541/acme-shop/.berth/attachments/20261027-134209-pasted-134209.png], then Read of both.
  • Structured driver. Transcript answer: this one is off [attached: /tmp/vb 2541/acme-web/.berth/attachments/20261027-134246-checkout-step-2.png, /tmp/vb 2541/acme-web/.berth/attachments/20261027-134248-pasted-134248.png], then Read of both.
  • Before, a first try quoted each path ("…"). The terminal driver passed, but on the structured driver the answered card showed this one is off [attached: once Claude's record came back, cut at the first quote. That's why the format uses commas.
Card, 80x24 terminal Answered Claude read them (terminal) Claude read them (structured)

dev-box.sh's trust wait, driven with a stubbed tmux: trust question → answered once → prompt; already trusted → straight on; neither → exit 1 with the screen; capture-pane failing → exit 1.

From the first round (before the rebase):

Mock, production build (drive.mjs chat-question-images, no console errors):

Reply box files on the card Submit waits for the upload Answered

Real Claude Code on a dev box, chat-question-images-live. Claude asks a question; the prompt says nothing about images. One image is dropped on the reply box and one pasted into the card. Both have words on them that only reading them reveals.

  • Terminal driver, pane at 80x24. Box log: answer ask: answered 1 questions. Transcript: Read: …-giraffe.png, …-pasted-163655.png. Claude: "One is an orange card reading "ORANGE GIRAFFE 7316" and the other a teal card reading "TEAL ANCHOR 0948"…"

  • Structured driver (Claude's SDK). answer sdk: answered 1 questions, two Reads. Claude: "…one is a plain orange card reading "ORANGE GIRAFFE 7316" and the other is a teal card reading "TEAL ANCHOR 0948"."

  • Answered in Claude's own terminal instead: the card closes and the image is back in the reply box.

Before: at 80x24 the same answer failed with Claude's form didn't take your words: it shows "this is the one that is off [attached: /tmp/verify-berthd-bo…". Real screen: testdata/answer/own-words-paths-80.txt.

Tests:

  • Before the box fix, TestDriveAttachedPathsOnAShortPane and TestReadFormRealScreens (the new fixture) failed; both pass now.
  • TestWordsAsWrapped: "use /tmp/a b" doesn't hold "use /tmp/ab", "now here" doesn't hold "nowhere", and a path broken at a line end does hold.
  • e2e chat.spec.ts:
    • "files in the reply box and dropped on the form go with its answer": Submit held while a 2.5 MB file uploads; the answer's paths are checked in what the mock box received.
    • "a screenshot pasted into the form's own words…": a failed submit keeps it; Retry sends it.
  • answer-attachments.test.ts covers the one-line format, round-trips paths with a space, a comma and brackets, and shownName with the same-second count.

Checks:

  • go vet: passes.
  • go test -race ./...: passes except tests that fail on origin/main on this machine too. TestTheCatalogIsCapped counts the machine's own commands. TestReviewRoutesOverTheWire, TestReviewSetupSays…, TestGitHubLooks…, TestDetach and TestAnSSHRouteThatFails… flake under load (after the rebase, TestAnSSHRouteThatFails… failed in the full run at load ~50 and then passed 5/5 on both this branch and origin/main): the same combination failed 1 in 3 on origin/main, and each passes on its own.
  • App: typecheck:plugins, check:*, pnpm test (583), pnpm build and tsc -p e2e pass.
  • e2e: chat, composer, drop and ask-card specs, 29 tests, pass. The new tests passed 5× repeated. After the rebase: the two attachment tests in chat.spec.ts pass, and drive.mjs chat-question-images (mock) passes.
  • cargo check can't run on this Linux VM (no GTK dev libraries); no Rust changed.

Pre-PR review: Codex review and adversarial-review. Fixed after review:

  • Whitespace-blind matching became wrap-aware.
  • A remounted form keeps its files in the answer.
  • Submit waits only on the files it sends.

Merge Danger

Door: two-way

Reverting restores the old card, reply box and screen check. Uploads still land in <worktree>/.berth/attachments as before. The box API and stored data are unchanged.

Blast Radius: chat

🤖 Generated with Claude Code

@vercel

vercel Bot commented Oct 25, 2026

Copy link
Copy Markdown

@Stener1 is attempting to deploy a commit to the seanbrydonio's projects Team on Vercel.

A member of the Team first needs to authorize it.

@Stener1

Stener1 commented Oct 25, 2026

Copy link
Copy Markdown
Contributor Author

This is a draft only because of the open-PR limit; it turns ready on its own when a slot frees. I can't add labels here, so could a maintainer add run-ci? The checks I ran locally are listed under Evidence.

@Stener1
Stener1 marked this pull request as ready for review October 26, 2026 09:21

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 16 files

Reply with feedback, questions, or to request a fix.

View guided diff | Re-trigger cubic

Comment thread docs/changelog.mdx Resolved
Comment thread app/src/lib/attachments.ts Resolved
Comment thread app/src/lib/attachments.ts Resolved
@Stener1
Stener1 force-pushed the question-card-images branch from ec26e31 to 2ef40c5 Compare October 27, 2026 13:52
@Stener1

Stener1 commented Oct 27, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto main (14 commits; the dev-box.sh conflict kept main's VERIFY_BOX_ADDR and this branch's trust step). The review fixes are in 2ef40c5. All 8 cubic threads were valid, and each is fixed and resolved. The one behaviour change is the answer format: paths are parted by , , so a path with a space stays one. Quotes would break Claude's SDK read-back. chat-question-images-live passes on both drivers from a box dir with a space in it. The evidence is in the body.

@Stener1
Stener1 force-pushed the question-card-images branch from 2ef40c5 to e4704cf Compare October 28, 2026 21:59
@Stener1

Stener1 commented Oct 28, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto main (71efa89, with #186 and #180 in). Conflicts:

  • dev-box.sh: kept main's VERIFY_DRIVER=claude structured session and restart. The trust wait now runs only in the terminal-session branch, since a structured session has no folder to trust.
  • conversation-pane.tsx: kept main's structured/atMenu changes; the attach target sits beside them.
  • features/README.md: kept main's ask-card row and added the attachments row.
  • changelog.mdx: v0.3.31 had shipped, so the bullet moved to a new ## Unreleased.

No code changes besides those. After the rebase: go test -race on the box's answer tests, tsc, tsc -p e2e, check:titles/type/grid, the attachment unit tests and both attachment tests in chat.spec.ts pass. All 8 cubic threads were already fixed and resolved; nothing new to address. A maintainer still needs to add run-ci.

Stener1 and others added 2 commits October 29, 2026 20:21
Paste an image into a question's "Something else…" or drop files on the
card, and they go with the answer as their paths after the words, on one
line ("this one is off [attached: /…/shot.png]"), which Claude opens with
Read on the terminal and structured drivers alike. Images already in the
reply box, or dropped there while the question waits, show on the card
and go with it, then leave the reply box. Submit waits for the uploads
it sends; a submit that fails keeps them.

The box's terminal driver reads an answer back from Claude Code's form,
which breaks a path longer than a line in the middle: it now takes a
line break as a space or nothing, and only there.

The dev box no longer passes the caller's BERTH_* to its agents (a
structured worker's BERTH_DRIVER turned their hooks off), and no longer
re-sends the last prompt when its folder is already trusted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…a space

The paths after an answer's words are parted by ", " and the next path's
"/", so a worktree in a folder with a space, or a path with a bracket,
splits back into the same paths. Not quotes: on Claude's SDK the box reads
the answer back from Claude's "question"="answer" text, which doesn't
escape them. A name the box counted on (20261025-152924-1-shot.png) shows
as shot.png.

dev-box.sh waits for Claude's trust question or its prompt and stops when
neither shows, and its env quotes a box dir with a space. The live
scenario drops a file whose name has a space and none of the image's
words, waits for both words at once, and checks the answer again once
Claude's record has it. The changelog says files, not images.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Stener1
Stener1 force-pushed the question-card-images branch from e4704cf to 87567a5 Compare October 29, 2026 20:28

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant