works.iterative.claude.ui.transcript
Members list
Type members
Classlikes
A picture a host serves, ready to send.
A picture a host serves, ready to send.
The media type travels with the bytes because it decides how the browser reads them: it is the one thing that must not be guessed from the content.
Attributes
- Supertypes
-
trait Serializabletrait Producttrait Equalsclass Objecttrait Matchableclass AnyShow all
Markdown as a reader sees it.
Markdown as a reader sees it.
People and agents write to each other in markdown, so a transcript that shows **bold** shows characters nobody meant to write. Reading it is the job of this one place, on the JVM: the browser is handed prose that is already markup, which is what keeps a markdown parser out of the bundle and makes a server-rendered page and an element-rendered page the same page.
Everything the transcript wrote is escaped. Markdown's own syntax is the only thing that becomes markup, and two of its outcomes are refused:
- a link destination that would run code, which the renderer's own sanitizer drops
- an image, which would fetch bytes from somewhere else into the host's document. The card's rule is that an artifact is a reference and a media type, never bytes, so a markdown image is rendered as the reference it is.
Attributes
- Supertypes
-
class Objecttrait Matchableclass Any
- Self type
-
Markdown.type
The tree a producer emits.
The tree a producer emits.
The vocabulary is one thing but reaches a page two ways — as DOM built by the custom element, and as HTML written by a server. Describing the tree instead of building either one is what lets both say the same thing: the tags, the attributes and the nesting are decided once, in TranscriptMarkup, and a producer only knows how to walk this.
There are two leaves, and the difference between them is the point. Markup.Text is what a person or an agent wrote, which every producer escapes. Markup.Html is markup this module produced, and it can hold nothing but a Prose — a type no caller outside the transcript package can construct from transcript text. So a producer is never left deciding which of the two a value is.
Attributes
- Companion
- object
- Supertypes
-
trait Enumtrait Serializabletrait Producttrait Equalsclass Objecttrait Matchableclass AnyShow all
The vocabulary as the markup a page receives.
The vocabulary as the markup a page receives.
It walks a Markup and knows nothing about transcripts: what a conversation becomes is decided by TranscriptMarkup, and how it looks by the host's stylesheet. A host that renders its own pages places this markup where the transcript belongs; the element asks for it and inserts it. Both get the same characters, because there is one place they come from.
The two leaves of the tree are treated as the type says. Text is what a person or an agent wrote and is escaped, so a transcript that quotes HTML reads as the characters somebody typed. Prose is markup this module rendered and is written as it is — and no caller outside this package can make one from transcript text, so there is no path by which the second case carries the first.
scalatags does the escaping: a tag built with stringFrag or an attribute set with := runs its value through the same escaper, so <, >, & and " never read as markup wherever a transcript put them.
Attributes
- Supertypes
-
class Objecttrait Matchableclass Any
- Self type
-
MarkupHtml.type
The one line that stands for a longer body.
The one line that stands for a longer body.
A session is mostly activity, and a column of bare tool names answers nothing. The preview is what turns Bash into Bash — command: ls: the first line that carries anything, tidied of the indentation that file and command output arrive with, and cut where it would stop being one line.
A body arrives as the characters it is; a tool call arrives as its fields. Both end as one line, so the column of rows reads the same way down the page.
Attributes
- Supertypes
-
class Objecttrait Matchableclass Any
- Self type
-
Preview.type
The input of one tool call.
The input of one tool call.
Every agent tool defines its own input schema, so a call arrives as data of any shape. Writing that shape out as a line loses the one thing that makes a long call readable — which value belongs to which name — so it is kept, and the host styles it.
Three shapes cover what tool schemas use: one value, several values, and named parts. A number, a flag or an absent value is already a Value by the time it arrives: how a vendor writes its data as text is a question for the adapter that knows that vendor, never for a producer or a host.
Order is the contract's own. Named parts keep the order they were given, so the same call always reads the same way.
Attributes
- Supertypes
-
trait Enumtrait Serializabletrait Producttrait Equalsclass Objecttrait Matchableclass AnyShow all
One part of what came back from a call, in the order it came back.
One part of what came back from a call, in the order it came back.
An answer is not always writing. A tool that looks at a screen answers with a picture, and a tool that writes a file answers with the file. Both are artifacts — things the call produced rather than said — and neither crosses this wire as bytes.
A picture is named by where it sits: the call it came back from, and which part of that answer it is. So a page asks the host that served the transcript for it, and that host reads it out of the session it was already reading. A file is named and nothing more: its bytes are on the machine that ran the session, and offering to fetch them would turn a transcript into a way into that machine.
The parts keep the order they arrived in, because the words a tool wrote around a picture are about it.
Attributes
- Companion
- object
- Supertypes
-
trait Enumtrait Serializabletrait Producttrait Equalsclass Objecttrait Matchableclass AnyShow all
Attributes
- Companion
- enum
- Supertypes
-
trait Sumtrait Mirrorclass Objecttrait Matchableclass Any
- Self type
-
ToolOutput.type
One session's conversation as the reader sees it.
One session's conversation as the reader sees it.
Value parameters
- entries
-
the rows in conversation order, oldest first
- sessionId
-
the session this page was read from, echoed back so a page can be attributed to a conversation without trusting the request that asked for it
Attributes
- Companion
- object
- Supertypes
-
trait Serializabletrait Producttrait Equalsclass Objecttrait Matchableclass AnyShow all
Attributes
- Companion
- class
- Supertypes
-
trait Producttrait Mirrorclass Objecttrait Matchableclass Any
- Self type
-
Transcript.type
What a host serving transcripts must answer, described once.
What a host serving transcripts must answer, described once.
These are descriptions, not servers: a consumer attaches its own logic with serverLogic and interprets the result with whichever Tapir server matches the effect system it already runs — ZIO, cats-effect, Future, sync. That is why Tapir sits on this side of the module and not in the cross-built sources: the element reaches the same address with the browser's own fetch, so the browser bundle carries none of this.
The address is taken from TranscriptEndpoint, the one place the path and its parameter are written down, so the description and the URL the element builds cannot drift apart.
Attributes
- Supertypes
-
class Objecttrait Matchableclass Any
- Self type
-
TranscriptApi.type
The words a producer puts on an instant.
The words a producer puts on an instant.
An instant is a number and says nothing about whose morning it was, so turning one into a time and a day belongs to whoever knows the reader's timezone. That is the producer, and this is what it hands the vocabulary.
day is not only for showing. Two instants are on the same day exactly when it writes them the same way, so this is also what decides where a transcript crossed into a new day — no calendar arithmetic here, and the timezone that answers is the one the reader is being shown.
Every instant also rides on the elements as at, so a host that wants other words, or the reader's own timezone, has the value to work from.
Value parameters
- day
-
the day a moment fell on, as a reader reads it
- time
-
the wall-clock time of a moment, as a reader reads it
Attributes
- Supertypes
-
trait Serializabletrait Producttrait Equalsclass Objecttrait Matchableclass AnyShow all
Reads and writes Transcript as JSON.
Reads and writes Transcript as JSON.
The wire is a small closed vocabulary — user, agent, call, result, hook, activity — with times as epoch milliseconds and absent values simply left out. A call's input crosses as the shape it is, so the reader on the other side has the fields the tool was called with, and a call and its answer carry one call token, so the two rows stay one exchange. A message carries prose: the markup the host rendered its markdown to, so the reading is done once and every consumer shows the same page. An answer crosses as the parts it came back with, and an artifact among them as a reference — where the picture sits, or the path a file was written to — never as bytes. Written by hand rather than derived, so the shape is inspectable and stays identical on both platforms the contract is compiled for.
Reads are one-way tolerant: an entry whose kind this version does not know is dropped, so a page written by a newer writer still renders everything this reader understands instead of failing whole.
Attributes
- Supertypes
-
class Objecttrait Matchableclass Any
- Self type
-
TranscriptCodec.type
Where a reader asks for a session's transcript, and how that question is written down.
Where a reader asks for a session's transcript, and how that question is written down.
The description is deliberately free of any HTTP machinery: it is a path, a query parameter, and the two pure functions that write and read them. A host mounts it with whatever server it already runs; the client builds the same URL from the same source.
Attributes
- Supertypes
-
class Objecttrait Matchableclass Any
- Self type
-
TranscriptEndpoint.type
A single row of a conversation transcript.
A single row of a conversation transcript.
The categories are named after what a reader sees, not after any agent tool's log format: an agent tool reaches this model through an adapter, so the same few rows render a conversation whichever tool produced it.
A message carries Prose rather than the characters it was written in: people and agents write to each other in markdown, and reading it is the adapter's job, so every consumer of this model gets prose that is ready to show. detail on an activity is not prose — a tool's output is not writing, and is shown as the characters it is.
at is optional because not every source timestamps every row.
Attributes
- Companion
- object
- Supertypes
-
trait Enumtrait Serializabletrait Producttrait Equalsclass Objecttrait Matchableclass AnyShow all
Attributes
- Companion
- enum
- Supertypes
-
trait Sumtrait Mirrorclass Objecttrait Matchableclass Any
- Self type
-
TranscriptEntry.type
Why a transcript could not be delivered.
Why a transcript could not be delivered.
A reader who asked for a session and got nothing needs to know which of these happened — a mistyped id reads very differently from an archive that cannot be opened. Each case carries the words to show and the HTTP status a host answers with; the status is a plain number, so describing it costs the contract no server dependency.
Attributes
- Companion
- object
- Supertypes
-
trait Enumtrait Serializabletrait Producttrait Equalsclass Objecttrait Matchableclass AnyShow all
Attributes
- Companion
- enum
- Supertypes
-
trait Sumtrait Mirrorclass Objecttrait Matchableclass Any
- Self type
-
TranscriptFailure.type
Turns what a conversation archive gives back into what the endpoint owes.
Turns what a conversation archive gives back into what the endpoint owes.
Both directions are pure functions, so a host's own logic is reduced to the one effectful step it cannot avoid — reading the archive — and every consumer, on whichever effect system, answers a given session identically.
Attributes
- Supertypes
-
class Objecttrait Matchableclass Any
- Self type
-
TranscriptHistory.type
A transcript as the elements a host styles.
A transcript as the elements a host styles.
The vocabulary is semantic and prefixed: cc-transcript, cc-message, cc-activity, and the parts inside them. A host selects by tag and by attribute — cc-message[from="agent"], cc-activity[label="Bash"] — with the whole CSS language available, because the elements live in the page's own DOM and carry no style of their own. Choosing how a transcript looks is the host's, and nothing here takes it back.
A tool call is its own element rather than one more activity, because it has a shape a reader needs: the fields it was called with, each of them an element a host can select by the name the tool gave it. So is the answer to one, and both rows carry the token of the exchange they belong to, so a host can join a call to what came back from it.
Two things stay HTML's. Disclosure is details/summary wherever there is anything to open, so a row opens by the browser's own machinery rather than by a script, and keeps the keyboard behaviour that comes with it. Prose inside cc-body is HTML too — headings, lists, code, tables, as the writer marked them up. We own the structure of a conversation; HTML owns the rest.
The clock text is the producer's, because only the producer knows whose timezone to read the instant in. The instant itself rides along as the at attribute, so a host that wants a different format has the value.
Attributes
- Supertypes
-
class Objecttrait Matchableclass Any
- Self type
-
TranscriptMarkup.type
Types
A message's words, as the markup that shows them.
A message's words, as the markup that shows them.
A transcript is written by people and by agents, and both write characters that mean something to HTML. The card's rule is that prose markup is ours or it is not inserted, and this type is how that is held by construction rather than by care: the only way to obtain a Prose from outside this package is Markdown.prose, which escapes everything the transcript wrote and passes through only the markup it decided on itself.
Producers therefore never face the question. A producer is handed prose that is already safe to place, and transcript text reaches it only as a text leaf of the markup tree, which every producer escapes.