In progress. The current tree has the shared marker data model, session persistence, marker CRUD routes, marker SSE deltas, frontend API helpers, live delta application, overview-rail marker pins, transcript chips, marker list/previous-next navigation, and a quick checkpoint action on transcript messages. Full marker edit/delete UI and agent workflow actions are still pending.
Conversation markers are durable, user-visible anchors inside an agent conversation. They let the user mark important points in a long transcript, name and color those points, jump between them, and optionally ask agents to use them as context boundaries.
Related feature: Conversation Overview Map.
TermAl conversations can become long quickly: streamed reasoning, tool output, diffs, code review notes, approvals, retries, and parallel-agent summaries can all land in the same transcript. The existing transcript is chronological, but it has no first-class way to preserve the user’s mental landmarks.
Common user needs:
Today the fallback is plain text in the conversation or an external note. Both are lossy: they are hard to navigate, not typed, not stable under transcript virtualization, and not available to future UI workflows.
A marker is a durable annotation attached to a session and anchored to one or more messages.
type ConversationMarkerKind =
| "checkpoint"
| "decision"
| "review"
| "bug"
| "question"
| "handoff"
| "custom";
type ConversationMarker = {
id: string;
sessionId: string;
kind: ConversationMarkerKind;
name: string;
body?: string | null;
color: string;
messageId: string;
messageIndexHint: number;
endMessageId?: string | null;
endMessageIndexHint?: number | null;
createdAt: string;
updatedAt: string;
createdBy: "user" | "agent" | "system";
};
Rules:
messageId is the primary anchor.messageIndexHint is a recovery hint only. It is not authoritative.name is the short user-facing label shown in marker rows, lists, and
navigation controls.color is required and should be stored as a theme token or validated CSS
color, not inferred only from marker kind.endMessageId; single-message markers leave it null.V1 should ship with a small fixed set:
checkpoint: a user-defined resume point.decision: an accepted architectural/product decision.review: review feedback or review boundary.bug: a reproduced issue or failure point.question: an unresolved question to revisit.handoff: a point intended for a later agent or human handoff.custom: user-defined label with no special behavior.Type-specific behavior should stay minimal in v1. The type mostly controls icon, default color, default name suggestion, and filter grouping. The user can override marker color without changing the marker kind.
Entry points:
Add markerMark range/marker <kind> <title>Creation form:
Default name/color suggestions:
Checkpoint, blueReview feedback, amberBug: <nearest error summary>, redQuestion, violetHandoff point, cyanMarkers should be visible but not noisy.
Recommended v1 rendering:
Actions:
Show markers window / Hide markers windowEdit markerCopy marker linkJump to markerDelete markerSend from marker or Continue from marker can be added after v1.Add a compact floating marker window inside the session pane. It should stay within the tab pane view, not portal to global app chrome.
List item fields:
List behavior:
The conversation toolbar should expose marker navigation independent of search.
Controls:
Previous markerNext markerbug markersOrdering:
messageIndex, then createdAt, then id.Behavior:
Jumping to a marker must work with transcript virtualization.
Flow:
messageId.Markers should persist with the session state in the same local persistence domain as sessions.
Suggested Rust shape:
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
struct ConversationMarker {
id: String,
session_id: String,
kind: ConversationMarkerKind,
name: String,
body: Option<String>,
color: String,
message_id: String,
message_index_hint: usize,
end_message_id: Option<String>,
end_message_index_hint: Option<usize>,
created_at: String,
updated_at: String,
created_by: MarkerAuthor,
}
Storage options:
conversation_markers table keyed by
(session_id, marker_id).Markers are metadata. They should not be inserted into messages, because
that would affect prompt history, transcript count, and agent-visible content.
Initial routes:
GET /api/sessions/{sessionId}/markersPOST /api/sessions/{sessionId}/markersPATCH /api/sessions/{sessionId}/markers/{markerId}DELETE /api/sessions/{sessionId}/markers/{markerId}Optional later routes:
POST /api/sessions/{sessionId}/markers/{markerId}/jump-contextGET /api/sessions/{sessionId}/markers/exportMutation behavior:
Marker changes should be delta-friendly.
type SessionMarkerDelta =
| {
type: "conversationMarkerCreated";
revision: number;
sessionId: string;
marker: ConversationMarker;
sessionMutationStamp?: number | null;
}
| {
type: "conversationMarkerUpdated";
revision: number;
sessionId: string;
marker: ConversationMarker;
sessionMutationStamp?: number | null;
}
| {
type: "conversationMarkerDeleted";
revision: number;
sessionId: string;
markerId: string;
sessionMutationStamp?: number | null;
};
Frontend application rules:
messagesLoaded === false.V1 markers are user-created, but they should be useful to agents.
Recommended prompt insertion actions:
Continue from markerSummarize since markerReview changes since markerUse marker as handoff contextThese actions should produce explicit user prompts that reference marker title, session id, and anchor message id. They should not silently alter hidden context.
Example handoff prompt:
Continue from conversation marker "Accepted architecture decision"
in session session-42 at message msg-88. Use the marker note as the
handoff boundary and review messages after that point.
Markers should integrate with transcript search as metadata results:
Do not force full transcript hydration just to list markers. The marker list should be available from session metadata.
Rules:
markers field means no markers.custom with the original value preserved
if practical.name and color fields.Continue from marker, Summarize since marker, and
Use as handoff actions.Backend:
Frontend:
messagesLoaded === falseVirtualization:
Agent workflow:
Continue from marker inserts a deterministic prompt