Documentation
¶
Overview ¶
Package discussion defines types for server-generated discussion artifacts.
Discussion Directory Layout ¶
Each recorded discussion (audio or video) lives in a directory under the team context's discussions/ folder:
discussions/2026-03-20-1423-person/ ├── metadata.json # recording identity (title, created_at, user_id) ├── summary.md # human-written prose summary from recording UI ├── transcript.vtt # WebVTT transcript (speaker-tagged cues) ├── summary.json # server-generated: structural skeleton (this package) ├── annotations.json # server-generated: timestamped evidence (this package) └── keyframes.json # server-generated: video-only visual frames (this package)
Audio recordings produce the same artifacts minus keyframes.json.
summary.json vs annotations.json ¶
These two files serve different purposes in the progressive disclosure model.
summary.json is the STRUCTURAL SKELETON — it answers "what was discussed, in what order, and how important was each segment?"
- Chapter-level granularity (segments of minutes)
- Contains synthesized summaries, importance rankings, topic tags
- Top-level categorized facts (decisions, learnings, etc.)
- Primary use: L1 progressive disclosure — agents decide which chapter to drill into
annotations.json is ANCHORED EVIDENCE — it answers "where exactly did this decision/disagreement/insight occur?"
- Moment-level granularity (specific cue ranges)
- Contains verbatim-adjacent extractions with VTT timestamps
- Primary use: L2 progressive disclosure — agents need specific evidence
Progressive Disclosure Layers ¶
L0 DISCUSSIONS.md / distilled-discussions.md — always loaded (~20-40 tokens/discussion) L1 summary.json chapters — on topic match (~500-1000 tokens) L2 annotations.json + keyframes.json index — need details (~300 tokens/chapter) L3 keyframe image via vision model — need visual (~1000 tokens/image) L4 VTT cue range — need verbatim (<200 tokens/range)
Index ¶
- Constants
- func AllVisualTypes(keyframes *KeyframesManifest) []string
- func VisualTypes(keyframes *KeyframesManifest, chapterID string) []string
- type ActionItem
- type Annotation
- type AnnotationsFile
- type Chapter
- type Decision
- type DiscussionSummary
- type Keyframe
- type KeyframesManifest
- type Learning
- type OpenQuestion
- type Requirement
- type TechnicalContext
Constants ¶
const ( ContentTypeDiagram = "diagram" ContentTypeCode = "code" ContentTypeTerminal = "terminal" ContentTypeSlide = "slide" ContentTypeUI = "ui" ContentTypeWireframe = "wireframe" ContentTypeLiveUI = "live-ui" ContentTypeTransition = "transition" ContentTypeOther = "other" )
ContentTypes for Keyframe.ContentType filtering. Server vision model (sageox-mono analyze_keyframes_vision.go) produces these values.
const ( AnnotationDecision = "decision" AnnotationActionItem = "action-item" AnnotationDisagreement = "disagreement" AnnotationQuestion = "question" AnnotationInsight = "insight" AnnotationLearning = "learning" AnnotationTangent = "tangent" AnnotationConsensus = "consensus" )
AnnotationTypes for Annotation.Type filtering (kebab-case per AGENTS.md convention).
Variables ¶
This section is empty.
Functions ¶
func AllVisualTypes ¶
func AllVisualTypes(keyframes *KeyframesManifest) []string
AllVisualTypes returns the sorted unique set of content types across all keyframes. Returns nil if the manifest is nil or contains no visual content.
func VisualTypes ¶
func VisualTypes(keyframes *KeyframesManifest, chapterID string) []string
VisualTypes returns the sorted unique set of content types from keyframes linked to the given chapter. Returns nil if no visual keyframes exist for this chapter.
Types ¶
type ActionItem ¶
type ActionItem struct {
Description string `json:"description"`
Assignee string `json:"assignee,omitempty"`
DueDate string `json:"due_date,omitempty"`
}
ActionItem records a task identified during the discussion.
func (ActionItem) Text ¶
func (a ActionItem) Text() string
Text returns a one-line representation for the LLM-bypass fast path.
type Annotation ¶
type Annotation struct {
Type string `json:"type"` // see Annotation* constants
Content string `json:"content"` // the annotation text
ChapterID string `json:"chapter_id,omitempty"` // links to Chapter.ID
CueRange [2]int `json:"cue_range"` // [start, end] VTT cue indices
Importance float64 `json:"importance,omitempty"` // 0.0-1.0
Speakers []string `json:"speakers,omitempty"` // who spoke
}
Annotation is a structured extraction anchored to a specific moment in the discussion. ChapterID links to the relevant Chapter. CueRange marks the VTT cue indices for verbatim lookup (L4).
type AnnotationsFile ¶
type AnnotationsFile struct {
SchemaVersion int `json:"schema_version"`
RecordingID string `json:"recording_id"`
GeneratedAt string `json:"generated_at"`
Annotations []Annotation `json:"annotations"`
}
AnnotationsFile represents annotations.json — timestamped evidence from the discussion. Each annotation is anchored to a chapter and a VTT cue range, providing provenance for decisions, disagreements, and action items.
func LoadAnnotations ¶
func LoadAnnotations(dirPath string) (*AnnotationsFile, error)
LoadAnnotations reads and parses annotations.json from a discussion directory. Returns nil if the file doesn't exist.
type Chapter ¶
type Chapter struct {
ID string `json:"id"` // e.g. "ch-1", "ch-2"
Title string `json:"title"` // semantic title
Summary string `json:"summary"` // brief chapter summary
CueRange [2]int `json:"cue_range"` // [start, end] VTT cue indices
TimeRange [2]float64 `json:"time_range"` // [start, end] seconds from start
Importance float64 `json:"importance"` // 0.0-1.0; >0.5 is significant
Topics []string `json:"topics,omitempty"` // topic tags
}
Chapter is a semantic section of a discussion with importance scoring. Different from sessionsummary.ChapterSummary which tracks coding session tool usage.
Agents use Importance to decide whether to drill deeper: chapters above the high-importance threshold are considered significant.
type Decision ¶
type Decision struct {
Description string `json:"description"`
Owner string `json:"owner,omitempty"`
Context string `json:"context,omitempty"`
}
Decision records a decision made during the discussion.
type DiscussionSummary ¶
type DiscussionSummary struct {
SchemaVersion int `json:"schema_version"`
RecordingID string `json:"recording_id"`
Title string `json:"title"`
HumanSummary string `json:"human_summary"`
RecordedAt string `json:"recorded_at,omitempty"`
DurationSeconds float64 `json:"duration_seconds,omitempty"`
Decisions []Decision `json:"decisions,omitempty"`
ActionItems []ActionItem `json:"action_items,omitempty"`
Requirements []Requirement `json:"requirements,omitempty"`
OpenQuestions []OpenQuestion `json:"open_questions,omitempty"`
Learnings []Learning `json:"learnings,omitempty"`
TechnicalContext TechnicalContext `json:"technical_context,omitempty"`
Constraints []string `json:"constraints,omitempty"`
NonGoals []string `json:"non_goals,omitempty"`
Topics []string `json:"topics,omitempty"`
Chapters []Chapter `json:"chapters,omitempty"`
HasAnnotations bool `json:"has_annotations,omitempty"`
HasKeyframes bool `json:"has_keyframes"`
}
DiscussionSummary represents a server-generated summary.json. Facts are FLAT at the top level — there is no agent_summary wrapper. Source of truth: packages/transcript-go/schema.go in the monorepo.
func LoadSummary ¶
func LoadSummary(dirPath string) (*DiscussionSummary, error)
LoadSummary reads and parses summary.json from a discussion directory. Returns nil if the file doesn't exist (not all discussions have server-generated summaries yet).
func (*DiscussionSummary) HasCategorizedFacts ¶
func (s *DiscussionSummary) HasCategorizedFacts() bool
HasCategorizedFacts returns true when the server pipeline has populated at least one top-level fact category. When true, consumers should use these directly and skip LLM extraction.
type Keyframe ¶
type Keyframe struct {
S3Key string `json:"s3_key"`
TimestampSeconds float64 `json:"timestamp_seconds"`
ExtractionMethod string `json:"extraction_method"` // e.g. "scene-change", "periodic"
SceneChangeScore float64 `json:"scene_change_score,omitempty"`
TranscriptCue string `json:"transcript_cue,omitempty"` // nearby transcript text
ChapterID string `json:"chapter_id,omitempty"` // links to Chapter.ID
ContentType string `json:"content_type,omitempty"` // "diagram", "code", "terminal", "slide", "ui", "other"
Description string `json:"description,omitempty"` // one-line text summary of what's visible
}
Keyframe is a single extracted video frame with semantic metadata. Description is the key field — it makes visual content searchable and lets agents decide whether to load the actual image (L3) or stop at the text description (L2).
func KeyframesForChapter ¶
func KeyframesForChapter(keyframes *KeyframesManifest, chapterID string) []Keyframe
KeyframesForChapter returns keyframes linked to the given chapter, sorted by timestamp. Returns nil if the manifest is nil or no keyframes match.
type KeyframesManifest ¶
type KeyframesManifest struct {
RecordingID string `json:"recording_id"`
SourceURL string `json:"source_url,omitempty"`
Duration float64 `json:"duration"`
KeyframeCount int `json:"keyframe_count"`
TotalBeforeDedup int `json:"total_before_dedup"`
Keyframes []Keyframe `json:"keyframes"`
}
KeyframesManifest represents keyframes.json — video-only, absent for audio recordings. Lets agents decide whether to load actual images based on text descriptions (L2).
func LoadKeyframes ¶
func LoadKeyframes(dirPath string) (*KeyframesManifest, error)
LoadKeyframes reads and parses keyframes.json from a discussion directory. Returns nil if the file doesn't exist.
type Learning ¶
type Learning struct {
Description string `json:"description"`
Source string `json:"source,omitempty"`
}
Learning records something the team learned during the discussion.
type OpenQuestion ¶
type OpenQuestion struct {
Question string `json:"question"`
Context string `json:"context,omitempty"`
}
OpenQuestion records an unresolved question from the discussion.
func (OpenQuestion) Text ¶
func (q OpenQuestion) Text() string
Text returns a one-line representation for the LLM-bypass fast path.
type Requirement ¶
type Requirement struct {
Description string `json:"description"`
Priority string `json:"priority,omitempty"`
Source string `json:"source,omitempty"`
}
Requirement records a requirement identified during the discussion.
func (Requirement) Text ¶
func (r Requirement) Text() string
Text returns a one-line representation for the LLM-bypass fast path.
type TechnicalContext ¶
type TechnicalContext struct {
Technologies []string `json:"technologies,omitempty"`
Architecture []string `json:"architecture,omitempty"`
Integrations []string `json:"integrations,omitempty"`
Notes []string `json:"notes,omitempty"`
}
TechnicalContext captures the technical landscape discussed. Notes holds free-form context that doesn't fit the three sub-categories.