Stream attachments end to end, ship files to a remote session's machine, and write up the transcript work

Uploads no longer sit whole in memory anywhere: the phone writes the
multipart body chunked as it reads the picked file, and the server writes
each chunk to a `.part` file under the session and renames it when whole.
The per-request cap is 4 GB and bounds disk, not memory.

A file attached to a session on another machine is copied there in the
same request: one ssh invocation takes the bytes on stdin into the
setup's `attachmentsDir` (new, optional, on the machine form and in the
config), else the session's cwd, else the login home, and answers with
`pwd -P`, which is recorded beside the file as `<name>.remote` and is the
path the driver tells the CLI. A failed copy fails the upload and says
why, so no message ever names a file that is not there. The host keeps
its copy so transcripts can reference and fetch it. Measured against the
Gentoo test guest: a 40 MB file shared from the phone arrived there byte
for byte. The tilde in that setting is the remote home, so it is not
expanded on the server the way other setup paths are.

TRANSCRIPT_RENDERING.md records the week of transcript work -- the
measurements behind each decision, the harness, what was rejected, and
what to do next -- so a new session can start from it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
irisandClaude Fable 5.1 committed 2026-09-03 13:24:36 -04:00
1 parent 6180663f14
commit 801618ba0e
12 files changed
+499 -57

No files matched your search

+11 -3
View File
@@ -5,6 +5,11 @@ replacing the Claude app for daily use. Rust/Axum backend on the desktop,
Kotlin/Compose Android app, WireGuard + pinned self-signed TLS + bearer token
between them.
**`TRANSCRIPT_RENDERING.md` is the record of the transcript work** --
measurements, techniques, the harness, and the ordered list of what is
next. Read it before touching anything under `Markdown*.kt`,
`Transcript*.kt` or `SessionScreen.kt`'s list.
**`PLAN.md` is the design source of truth.** Read it before building or
changing anything structural. It records every decision with its date, its
rationale, and the alternatives that were rejected and why — keep that habit
@@ -75,9 +80,12 @@ repo is in PLAN.md's "Backend layout" section.
and `isImageRef` on the phone tell the two apart; keep those lists
level. The phone attaches from the photo picker, the file chooser and
Android's share sheet (`Share.kt`; the manifest's SEND filter), all
through one `attach` path in `SessionScreen`. Files exist only on the
server's machine -- see PLAN.md's "Transport" for what that means for
remote sessions.
through one `attach` path in `SessionScreen`, streamed both from the
phone and onto disk. A file for a session on another machine is also
copied there during the upload (setup's `attachmentsDir`, else the
session's cwd, else home) and the driver names that path, read from
the `<name>.remote` marker beside the file -- PLAN.md's "Transport" has
the reasoning.
- `server/` — Rust backend (`ai-server`). `main.rs` bootstraps (TLS, the
auth layer, token/QR enrollment, wg0 binding), `routes.rs` has the HTTP
table in its module doc comment, `auth.rs` the bearer-token middleware,