personal memory agent
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

refactor(journal-skill): split docs/JOURNAL.md into talent/journal/references/*

Move the journal layout and CLI material out of docs/JOURNAL.md into the
journal skill package, with dedicated reference files for configuration,
facets, captures, logs, storage, and CLI usage.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

+1418 -1362
+3 -1081
docs/JOURNAL.md
··· 1 1 # Sol Journal 2 2 3 - > **First rule for AI agents in a journal**: before doing anything else, run `sol call identity` to hydrate Sol's self, partner, agency, and awareness. The output of that command tells you who you are, who you're working with, and what's currently on your plate. Everything below describes the journal's *layout* — the dynamic identity context comes from the CLI. 4 - 5 - # Journal Layout 6 - 7 - This document describes the layout of a **journal** directory where all captures, extracts, and insights are stored. Each dated `YYYYMMDD` folder is referred to as a **day**, and within each day captured content is organized into **segments** (timestamped duration folders). Each segment folder uses the format `HHMMSS_LEN/` where `HHMMSS` is the start time and `LEN` is the duration in seconds. This folder name serves as the **segment key**, uniquely identifying the segment within a given day. 8 - 9 - ## The Three-Layer Architecture 10 - 11 - solstone transforms raw recordings into actionable understanding through a three-layer pipeline: 12 - 13 - ``` 14 - ┌─────────────────────────────────────┐ 15 - │ LAYER 3: AGENT OUTPUTS │ Narrative summaries 16 - │ (Markdown files) │ "What it means" 17 - │ - talents/*.md (daily outputs) │ 18 - │ - *.md (segment outputs) │ 19 - └─────────────────────────────────────┘ 20 - ↑ synthesized from 21 - ┌─────────────────────────────────────┐ 22 - │ LAYER 2: EXTRACTS │ Structured data 23 - │ (JSON/JSONL files) │ "What happened" 24 - │ - audio.jsonl, *_audio.jsonl │ 25 - │ - screen.jsonl, *_screen.jsonl │ 26 - │ - events/*.jsonl (per-facet) │ 27 - └─────────────────────────────────────┘ 28 - ↑ derived from 29 - ┌─────────────────────────────────────┐ 30 - │ LAYER 1: CAPTURES │ Raw recordings 31 - │ (Binary media files) │ "What was recorded" 32 - │ - *.flac, *.ogg, *.opus, *.wav (audio) │ 33 - │ - *.webm (video) │ 34 - └─────────────────────────────────────┘ 35 - ``` 36 - 37 - ### Vocabulary Quick Reference 38 - 39 - **Pipeline Layers** 40 - 41 - | Term | Definition | Examples | 42 - |------|------------|----------| 43 - | **Capture** | Raw audio/video recording | `*.flac`, `*.ogg`, `*.opus`, `*.wav`, `*.webm` | 44 - | **Extract** | Structured data from captures | `*.jsonl` | 45 - | **Agent Output** | AI-generated narrative summary | `talents/*.md`, `HHMMSS_LEN/*.md` | 46 - 47 - **Organization** 48 - 49 - | Term | Definition | Examples | 50 - |------|------------|----------| 51 - | **Day** | 24-hour activity directory | `20250119/` | 52 - | **Segment** | 5-minute time window | `143022_300/` (14:30:22, 5 min) | 53 - | **Span** | Sequential segment group | Import creating 3 segments | 54 - | **Facet** | Project/context scope | `#work`, `#personal` | 55 - 56 - **Extracted Data** 57 - 58 - | Term | Definition | Examples | 59 - |------|------------|----------| 60 - | **Entity** | Tracked person/project/concept | People, companies, tools | 61 - | **Occurrence** | Time-based event | Meetings, messages, files | 62 - 63 - ## Top-Level Directory Structure 64 - 65 - | Directory/File | Purpose | 66 - |----------------|---------| 67 - | `chronicle/` | Container for daily capture folders (`YYYYMMDD/`) containing segments, extracts, and agent outputs | 68 - | `entities/` | Journal-level entity identity records (`<id>/entity.json`) | 69 - | `facets/` | Facet-specific data: entity relationships, todos, events, news, action logs | 70 - | `talents/` | Talent run logs in per-talent subdirectories (`<name>/<id>.jsonl`), day indexes (`<day>.jsonl`), and latest-run symlinks (`<name>.log`) | 71 - | `apps/` | App-specific storage (distinct from codebase `apps/`) | 72 - | `streams/` | Per-stream state files (`<name>.json`) tracking segment chains and sequence numbers | 73 - | `imports/` | Imported audio files and processing artifacts | 74 - | `tokens/` | Token usage logs from AI model calls, organized by day | 75 - | `indexer/` | Search index (`journal.sqlite` FTS5 database) | 76 - | `health/` | Service health logs (`<service>.log` files) | 77 - | `config/` | Configuration files and journal-level action logs | 78 - | `task_log.txt` | Optional log of utility runs in `[epoch]\tmessage` format | 79 - | `summary.md` | Journal-wide statistics summary (generated by `sol journal-stats`) | 80 - | `stats.json` | Detailed journal statistics in JSON format (generated by `sol journal-stats`) | 81 - 82 - ### Config directory 83 - 84 - - `config/journal.json` – owner configuration for the journal (optional, see [Owner configuration](#owner-configuration)). 85 - - `config/convey.json` – Convey UI preferences (facet/app ordering, selected facet). 86 - - `config/actions/` – journal-level action logs (see [Action Logs](#action-logs)). 87 - 88 - ## Owner configuration 89 - 90 - The optional `config/journal.json` file allows customization of journal processing and presentation based on owner preferences. This file should be created at the journal root and contains personal settings that affect how the system processes and interprets journal data. 91 - 92 - ### Identity configuration 93 - 94 - The `identity` block contains information about the journal owner that helps tools correctly identify the owner in transcripts, meetings, and other captured content: 95 - 96 - ```json 97 - { 98 - "identity": { 99 - "name": "Jeremie Miller", 100 - "preferred": "Jer", 101 - "pronouns": { 102 - "subject": "he", 103 - "object": "him", 104 - "possessive": "his", 105 - "reflexive": "himself" 106 - }, 107 - "aliases": ["Jer", "jeremie"], 108 - "email_addresses": ["jer@example.com"], 109 - "timezone": "America/Los_Angeles" 110 - } 111 - } 112 - ``` 113 - 114 - Fields: 115 - - `name` (string) – Full legal or formal name of the journal owner 116 - - `preferred` (string) – Preferred name or nickname to be used when addressing the owner 117 - - `pronouns` (object) – Structured pronoun set for template usage with fields: 118 - - `subject` – Subject pronoun (e.g., "he", "she", "they") 119 - - `object` – Object pronoun (e.g., "him", "her", "them") 120 - - `possessive` – Possessive adjective (e.g., "his", "her", "their") 121 - - `reflexive` – Reflexive pronoun (e.g., "himself", "herself", "themselves") 122 - - `aliases` (array of strings) – Alternative names, nicknames, or usernames that may appear in transcripts 123 - - `email_addresses` (array of strings) – Email addresses associated with the owner for participant detection 124 - - `timezone` (string) – IANA timezone identifier (e.g., "America/New_York", "Europe/London") for timestamp interpretation 125 - 126 - This configuration helps meeting extraction identify the owner as a participant, enables personalized agent interactions, and ensures timestamps are interpreted correctly across the journal. 127 - 128 - ### Convey configuration 129 - 130 - The `convey` block contains settings for the web application: 131 - 132 - ```json 133 - { 134 - "convey": { 135 - "password_hash": "<set via sol password set>" 136 - } 137 - } 138 - ``` 139 - 140 - Fields: 141 - - `password_hash` (string) – Hashed password for accessing the convey web application. Set via `sol password set`. 142 - 143 - **UI Preferences:** The separate `config/convey.json` file stores UI/UX personalization (facet/app ordering, selected facet). All fields optional: 144 - 145 - ```json 146 - { 147 - "facets": {"order": ["work", "personal"], "selected": "work"}, 148 - "apps": {"order": ["home", "calendar", "todos"], "starred": ["home", "todos"]} 149 - } 150 - ``` 151 - 152 - - `facets.order` – Custom facet ordering. `facets.selected` – Currently selected facet (auto-synced with browser). 153 - - `apps.order` – Custom app ordering in menu bar. 154 - - `apps.starred` – Apps to show in the quick-access starred section. 155 - 156 - ### Retention configuration 157 - 158 - The `retention` block controls automatic cleanup of layer 1 raw media (audio recordings, video captures, screen diffs) while preserving all layer 2 extracts and layer 3 agent outputs. Three modes control when raw media is deleted: 159 - 160 - - `"keep"` – retain raw media indefinitely 161 - - `"days"` – delete raw media after `raw_media_days` days, once the segment has finished processing (default: 7 days) 162 - - `"processed"` – delete raw media as soon as the segment has finished processing 163 - 164 - ```json 165 - { 166 - "retention": { 167 - "raw_media": "days", 168 - "raw_media_days": 30, 169 - "per_stream": { 170 - "plaud": { 171 - "raw_media": "days", 172 - "raw_media_days": 7 173 - }, 174 - "archon": { 175 - "raw_media": "processed" 176 - } 177 - } 178 - } 179 - } 180 - ``` 181 - 182 - Fields: 183 - - `raw_media` (string) – Retention mode: `"keep"`, `"days"`, or `"processed"`. Default: `"days"`. 184 - - `raw_media_days` (integer or null) – Number of days to retain raw media when mode is `"days"`. Default: `7`. Required when `raw_media` is `"days"`, ignored otherwise. 185 - - `per_stream` (object) – Per-stream overrides keyed by stream name. Each entry supports `raw_media` and `raw_media_days`. Omitted fields inherit from the global retention settings. 186 - 187 - "Raw media" means layer 1 capture files only: audio files (`.flac`, `.opus`, `.ogg`, `.m4a`, `.wav`), video files (`.webm`, `.mov`, `.mp4`), and screen diffs (`monitor_*_diff.png`). 188 - 189 - All layer 2 and layer 3 content is always preserved regardless of retention policy: transcripts (`audio.jsonl`, `screen.jsonl`), talent outputs (`talents/*.md`), speaker labels (`talents/speaker_labels.json`), facet events (`events/*.jsonl`), entity data, segment metadata (`stream.json`), and search index entries. 190 - 191 - Raw media is never deleted from segments that haven't finished processing. A segment is considered complete only when all four checks pass: 192 - 193 - - No `_active.jsonl` files in `talents/` (no running talents) 194 - - `audio.jsonl` (or `*_audio.jsonl`) exists if audio raw media was captured 195 - - `screen.jsonl` (or `*_screen.jsonl`) exists if video raw media was captured 196 - - `talents/speaker_labels.json` exists if voice embeddings (`.npz`) are present 197 - 198 - Purged segments remain fully navigable in convey. Transcripts, entities, speaker labels, and summaries are all intact. The only difference is that audio/video playback is unavailable. 199 - 200 - ### Environment variables 201 - 202 - The `env` block provides fallback values for environment variables. These are loaded at CLI startup and used when the corresponding variable is not set in the shell or `.env` file: 203 - 204 - ```json 205 - { 206 - "env": { 207 - "GOOGLE_API_KEY": "your-google-api-key", 208 - "ANTHROPIC_API_KEY": "your-anthropic-api-key", 209 - "OPENAI_API_KEY": "your-openai-api-key", 210 - "REVAI_ACCESS_TOKEN": "your-revai-token", 211 - "PLAUD_ACCESS_TOKEN": "your-plaud-token" 212 - } 213 - } 214 - ``` 215 - 216 - **Precedence order** (highest to lowest): 217 - 1. Shell environment variables 218 - 2. `.env` file in project root 219 - 3. Journal config `env` section 220 - 221 - This allows storing API keys in the journal config as an alternative to `.env`, which can be useful when the journal is synced across machines or when you want to keep all configuration in one place. 222 - 223 - #### Template usage examples 224 - 225 - The structured pronoun format enables proper pronoun usage in generated text and agent responses: 226 - 227 - ```python 228 - # In templates or generated text: 229 - f"{identity.pronouns.subject} joined the meeting" # "he joined the meeting" 230 - f"I spoke with {identity.pronouns.object}" # "I spoke with him" 231 - f"That is {identity.pronouns.possessive} desk" # "That is his desk" 232 - f"{identity.pronouns.subject} did it {identity.pronouns.reflexive}" # "he did it himself" 233 - ``` 234 - 235 - For complete documentation of the prompt template system including all variable categories, composition patterns, and how to add new variables, see [PROMPT_TEMPLATES.md](PROMPT_TEMPLATES.md). 236 - 237 - ### Transcribe configuration 238 - 239 - The `transcribe` block configures audio transcription settings for `sol transcribe`: 240 - 241 - ```json 242 - { 243 - "transcribe": { 244 - "backend": "whisper", 245 - "enrich": true, 246 - "preserve_all": false, 247 - "noise_upgrade_min_speech_ratio": 0.3, 248 - "whisper": { 249 - "device": "auto", 250 - "model": "medium.en", 251 - "compute_type": "default" 252 - }, 253 - "revai": { 254 - "model": "fusion" 255 - } 256 - } 257 - } 258 - ``` 259 - 260 - **Top-level fields:** 261 - - `backend` (string) – STT backend to use: `"whisper"` (local processing) or `"revai"` (cloud with speaker diarization). Default: `"whisper"`. 262 - - `enrich` (boolean) – Enable LLM enrichment for topic extraction and transcript correction. Default: `true`. 263 - - `preserve_all` (boolean) – Keep audio files even when no speech is detected. When `false`, silent recordings are deleted to save disk space. Default: `false`. 264 - - `noise_upgrade_min_speech_ratio` (number) – Min speech/loud ratio required for noisy upgrade (default: `0.3`). Filters out music and other non-speech noise. 265 - 266 - **Whisper backend settings** (`transcribe.whisper`): 267 - - `device` (string) – Device for inference: `"auto"` (detect GPU, fall back to CPU), `"cpu"`, or `"cuda"`. Default: `"auto"`. 268 - - `model` (string) – Whisper model to use (e.g., `"tiny.en"`, `"base.en"`, `"small.en"`, `"medium.en"`, `"large-v3-turbo"`, `"distil-large-v3"`). Default: `"medium.en"`. 269 - - `compute_type` (string) – Compute precision: `"default"` (auto-select optimal for platform), `"float32"` (most compatible), `"float16"` (faster on CUDA GPUs), `"int8"` (fastest on CPU). Default: `"default"`. 270 - 271 - **Rev.ai backend settings** (`transcribe.revai`): 272 - - `model` (string) – Rev.ai transcriber model: `"fusion"` (best quality), `"machine"` (fast automated), or `"low_cost"`. Default: `"fusion"`. 273 - 274 - **Platform auto-detection** (Whisper): When `compute_type` is `"default"`, optimal settings are automatically selected: 275 - - **CUDA GPU**: Uses `float16` for GPU-optimized inference 276 - - **CPU (including Apple Silicon)**: Uses `int8` for ~2x faster inference and significantly faster model loading 277 - 278 - Voice embeddings (resemblyzer) also auto-detect the best device: MPS on Apple Silicon (~16x faster), CUDA when available, or CPU fallback. 279 - 280 - CLI flags can override settings: `--backend` selects the backend, `--cpu` forces CPU mode with int8 (Whisper only), `--model MODEL` overrides the Whisper model. 281 - 282 - ### Describe configuration 283 - 284 - The `describe` block configures screen analysis settings for `sol describe`: 285 - 286 - ```json 287 - { 288 - "describe": { 289 - "max_extractions": 20, 290 - "categories": { 291 - "code": { 292 - "importance": "high", 293 - "extraction": "Extract when viewing different repositories or files" 294 - }, 295 - "gaming": { 296 - "importance": "ignore" 297 - } 298 - } 299 - } 300 - } 301 - ``` 302 - 303 - **Fields:** 304 - - `max_extractions` (integer) – Maximum number of frames to run detailed content extraction on per video. The first qualified frame is always extracted regardless of this limit. When more frames are eligible, selection uses AI-based prioritization (falling back to random selection). Default: `20`. 305 - - `categories` (object) – Per-category overrides for importance and extraction guidance. 306 - 307 - #### Category overrides 308 - 309 - Each category (e.g., `code`, `meeting`, `browsing`) can have: 310 - 311 - | Field | Values | Description | 312 - |-------|--------|-------------| 313 - | `importance` | `high`, `normal`, `low`, `ignore` | Advisory priority hint for AI frame selection. `high` prioritizes these frames, `low` deprioritizes unless unique, `ignore` suggests skipping unless categorization seems wrong. Default: `normal`. | 314 - | `extraction` | string | Custom guidance for when to extract content from this category. Overrides the default from the category's `.json` file. | 315 - 316 - Importance levels are advisory hints passed to the AI selection process, not hard filters. The AI may still select frames from `ignore` categories if it determines the content is valuable or the categorization may be incorrect. 317 - 318 - ### Providers configuration 319 - 320 - The `providers` block enables fine-grained control over which LLM provider and model is used for different contexts. This supports a tier-based system where you can specify capability levels (pro/flash/lite) rather than specific model names. 321 - 322 - ```json 323 - { 324 - "providers": { 325 - "default": { 326 - "provider": "google", 327 - "tier": 2 328 - }, 329 - "contexts": { 330 - "observe.*": {"provider": "google", "tier": 3}, 331 - "talent.system.*": {"tier": 1}, 332 - "talent.system.meetings": {"provider": "anthropic", "disabled": true}, 333 - "talent.entities.observer": {"tier": 2, "extract": false} 334 - }, 335 - "models": { 336 - "google": { 337 - "1": "gemini-3-pro-preview", 338 - "2": "gemini-3-flash-preview", 339 - "3": "gemini-2.5-flash-lite" 340 - } 341 - } 342 - } 343 - } 344 - ``` 345 - 346 - #### Tier system 347 - 348 - Tiers provide a provider-agnostic way to specify model capability levels: 349 - 350 - | Tier | Name | Description | 351 - |------|-------|-------------| 352 - | 1 | pro | Highest capability, best for complex reasoning | 353 - | 2 | flash | Balanced performance and cost (default) | 354 - | 3 | lite | Fastest and cheapest, for simple tasks | 355 - 356 - System defaults map tiers to models for each provider. See `think/models.py` for current tier-to-model mappings (`PROVIDER_DEFAULTS` constant). 357 - 358 - If a requested tier is unavailable for a provider, the system falls back to more capable tiers (e.g., tier 3 → tier 2 → tier 1). 359 - 360 - #### Context matching 361 - 362 - Contexts are matched in order of specificity: 363 - 1. **Exact match** – `"talent.system.meetings"` matches only that exact context 364 - 2. **Glob pattern** – `"observe.*"` matches any context starting with `observe.` 365 - 3. **Default** – Falls back to the `default` configuration 366 - 367 - #### Context naming convention 368 - 369 - Talent configs (agents and generators) use the pattern `talent.{source}.{name}`: 370 - - System configs: `talent.system.{name}` (e.g., `talent.system.meetings`, `talent.system.default`) 371 - - App configs: `talent.{app}.{name}` (e.g., `talent.entities.observer`, `talent.support.support`) 372 - 373 - Other contexts follow the pattern `{module}.{feature}[.{operation}]`: 374 - - Observe pipeline: `observe.describe.frame`, `observe.enrich`, `observe.transcribe.gemini` 375 - 376 - #### Configuration options 377 - 378 - **default** – Global defaults applied when no context matches: 379 - - `provider` (string) – Provider name: `"google"`, `"openai"`, or `"anthropic"`. Default: `"google"`. 380 - - `tier` (integer) – Tier number (1-3). Default: `2` (flash). 381 - - `model` (string) – Explicit model name (overrides tier if specified). 382 - 383 - **contexts** – Context-specific overrides. Each key is a context pattern, value is: 384 - - `provider` (string) – Override provider (optional, inherits from default). 385 - - `tier` (integer) – Tier number (optional). 386 - - `model` (string) – Explicit model name (optional, overrides tier). 387 - - `disabled` (boolean) – Disable this talent config (optional, talent contexts only). 388 - - `extract` (boolean) – Enable/disable event extraction for generators with occurrence/anticipation hooks (optional). 389 - 390 - **models** – Per-provider tier overrides. Maps provider name to tier-model mappings: 391 - ```json 392 - { 393 - "google": {"1": "gemini-3-pro-preview", "2": "gemini-3-flash-preview"}, 394 - "openai": {"2": "gpt-5-mini-custom"} 395 - } 396 - ``` 397 - 398 - Note: Tier keys in JSON must be strings (`"1"`, `"2"`, `"3"`) since JSON doesn't support integer keys. 399 - 400 - ## Facet folders 401 - 402 - The `facets/` directory provides a way to organize journal content by scope or focus area. Each facet represents a cohesive grouping of related activities, projects, or areas of interest. 403 - 404 - ### Facet structure 405 - 406 - Each facet is organized as `facets/<facet>/` where `<facet>` is a descriptive short unique name. When referencing facets in the system, use hashtags (e.g., `#personal` for the "Personal Life" facet, `#ml_research` for "Machine Learning Research"). Each facet folder contains: 407 - 408 - - `facet.json` – metadata file with facet title and description. 409 - - `activities/` – configured activities and completed activity records (see [Activity Records](#activity-records)). 410 - - `entities/` – entity relationships and detected entities (see [Facet Entities](#facet-entities)). 411 - - `todos/` – daily todo lists (see [Facet-Scoped Todos](#facet-scoped-todos)). 412 - - `events/` – extracted events per day (see [Event extracts](#event-extracts)). 413 - - `news/` – daily news and updates relevant to the facet (optional). 414 - - `logs/` – action audit logs for tool calls (optional, see [Action Logs](#action-logs)). 415 - 416 - ### Facet metadata 417 - 418 - The `facet.json` file contains basic information about the facet: 419 - 420 - ```json 421 - { 422 - "title": "Machine Learning Research", 423 - "description": "AI/ML research projects, experiments, and related activities", 424 - "color": "#4f46e5", 425 - "emoji": "🧠" 426 - } 427 - ``` 428 - 429 - Optional fields: 430 - - `color` – hex color code for the facet card background in the web UI 431 - - `emoji` – emoji icon displayed in the top-left of the facet card 432 - - `muted` – boolean flag to mute/hide the facet from views (default: false) 433 - - Muted facets are filtered out by `get_enabled_facets()`, so agents that iterate enabled facets, such as `entity_observer`, skip them silently. 434 - 435 - ### Facet Entities 436 - 437 - Entities in solstone use a two-tier architecture with **journal-level entities** (canonical identity) and **facet relationships** (per-facet context). There are also **detected entities** (daily discoveries) that can be promoted to attached status. 438 - 439 - #### Entity Storage Structure 440 - 441 - ``` 442 - entities/ 443 - └── {entity_id}/ 444 - └── entity.json # Journal-level entity (canonical identity) 445 - 446 - facets/{facet}/ 447 - └── entities/ 448 - ├── YYYYMMDD.jsonl # Daily detected entities 449 - └── {entity_id}/ 450 - ├── entity.json # Facet relationship 451 - ├── observations.jsonl # Durable facts (optional) 452 - └── voiceprints.npz # Voice recognition data (optional) 453 - ``` 454 - 455 - **Journal-level entities** (`entities/<id>/entity.json`) store the canonical identity: name, type, aliases (aka), and principal flag. These are shared across all facets. 456 - 457 - **Facet relationships** (`facets/<facet>/entities/<id>/entity.json`) store per-facet context: description, timestamps, and custom fields specific to that facet. 458 - 459 - **Entity memory** (observations, voiceprints) is stored alongside facet relationships. 460 - 461 - #### Journal-Level Entities 462 - 463 - Journal entities represent the canonical identity record: 464 - 465 - ```json 466 - { 467 - "id": "alice_johnson", 468 - "name": "Alice Johnson", 469 - "type": "Person", 470 - "aka": ["Ali", "AJ"], 471 - "is_principal": false, 472 - "created_at": 1704067200000 473 - } 474 - ``` 475 - 476 - **Standard fields:** 477 - - `id` (string) – Stable slug identifier derived from name via `entity_slug()` in `think/entities/` (lowercase, underscores, e.g., "Alice Johnson" → "alice_johnson"). Used for folder paths, URLs, and tool references. 478 - - `name` (string) – Display name for the entity. 479 - - `type` (string) – Entity type (e.g., "Person", "Company", "Project", "Tool"). Types are flexible and owner-defined; must be alphanumeric with spaces, minimum 3 characters. 480 - - `aka` (array of strings) – Alternative names, nicknames, or acronyms. Used in audio transcription and fuzzy matching. 481 - - `is_principal` (boolean) – When `true`, identifies this entity as the journal owner. Auto-flagged when name/aka matches identity config. 482 - - `blocked` (boolean) – When `true`, entity is hidden from all facets and excluded from agent context. 483 - - `created_at` (integer) – Unix timestamp in milliseconds when entity was created. 484 - 485 - #### Facet Relationships 486 - 487 - Facet relationships link journal entities to specific facets with context: 488 - 489 - ```json 490 - { 491 - "entity_id": "alice_johnson", 492 - "description": "Lead engineer on the API project", 493 - "attached_at": 1704067200000, 494 - "updated_at": 1704153600000, 495 - "last_seen": "20260115" 496 - } 497 - ``` 498 - 499 - **Relationship fields:** 500 - - `entity_id` (string) – Links to the journal entity. 501 - - `description` (string) – Facet-specific description. 502 - - `attached_at` (integer) – Unix timestamp when attached to this facet. 503 - - `updated_at` (integer) – Unix timestamp of last modification. 504 - - `last_seen` (string) – Day (YYYYMMDD) when last mentioned in journal content. 505 - - `detached` (boolean) – When `true`, soft-deleted from this facet but data preserved. 506 - - Custom fields (any) – Additional facet-specific metadata (e.g., `tier`, `status`, `priority`). 507 - 508 - #### Detected Entities 509 - 510 - Daily detection files (`facets/<facet>/entities/YYYYMMDD.jsonl`) contain entities automatically discovered by agents from journal content: 511 - 512 - ```jsonl 513 - {"type": "Person", "name": "Charlie Brown", "description": "Mentioned in standup meeting"} 514 - {"type": "Tool", "name": "React", "description": "Used in UI development work"} 515 - ``` 516 - 517 - #### Entity Lifecycle 518 - 519 - 1. **Detection**: Daily agents scan journal content and record entities in `facets/<facet>/entities/YYYYMMDD.jsonl` 520 - 2. **Aggregation**: Review agent tracks detection frequency across recent days 521 - 3. **Promotion**: Entities with 3+ detections are auto-promoted to attached, or owners manually promote via UI 522 - 4. **Persistence**: Creates journal entity + facet relationship; remains active until detached 523 - 5. **Detachment**: Sets `detached: true` on facet relationship, preserving all data 524 - 6. **Re-attachment**: Clears detached flag, restoring the entity with preserved history 525 - 7. **Blocking**: Sets `blocked: true` on journal entity and detaches from all facets 526 - 527 - #### Cross-Facet Behavior 528 - 529 - The same entity can be attached to multiple facets with independent descriptions and timestamps. When loading entities across all facets, the alphabetically-first facet wins for duplicates during aggregation. 530 - 531 - ### Facet News 532 - 533 - The `news/` directory provides a chronological record of news, updates, and external developments relevant to the facet. This allows tracking of industry news, research updates, regulatory changes, or any external information that impacts the facet's focus area. 534 - 535 - #### News organization 536 - 537 - News files are organized by date as `news/YYYYMMDD.md` where each file contains the day's relevant news items. Only create files for days that have news to record—sparse population is expected. 538 - 539 - #### News file format 540 - 541 - Each `YYYYMMDD.md` file is a markdown document with a consistent structure: 542 - 543 - ```markdown 544 - # 2025-01-18 News - Machine Learning Research 545 - 546 - ## OpenAI Announces New Model Architecture 547 - **Source:** techcrunch.com | **Time:** 09:15 548 - Summary of the announcement and its relevance to current research projects... 549 - 550 - ## Paper: "Efficient Attention Mechanisms in Transformers" 551 - **Source:** arxiv.org | **Time:** 14:30 552 - Key findings from the paper and potential applications... 553 - 554 - ## Google Research Updates Dataset License Terms 555 - **Source:** blog.google | **Time:** 16:45 556 - Changes to dataset licensing that may affect ongoing experiments... 557 - ``` 558 - 559 - #### News entry structure 560 - 561 - Each news entry should include: 562 - - **Title** – concise headline as a level 2 heading 563 - - **Source** – origin of the news (website, journal, etc.) 564 - - **Time** – optional time of publication or discovery (HH:MM format) 565 - - **Summary** – brief description focusing on relevance to the facet 566 - - **Impact** – optional notes on how this affects facet work 567 - 568 - #### News metadata 569 - 570 - Optionally, a `news.json` file can be maintained at the root of the news directory to track metadata: 571 - 572 - ```json 573 - { 574 - "last_updated": "2025-01-18", 575 - "sources": ["arxiv.org", "techcrunch.com", "nature.com"], 576 - "auto_fetch": false, 577 - "keywords": ["transformer", "attention", "llm", "research"] 578 - } 579 - ``` 580 - 581 - This allows for future automation of news gathering while maintaining manual curation quality. 582 - 583 - ### Activity Records 584 - 585 - The `activities/` directory within each facet stores both the configured activity types (`activities.jsonl`) and completed activity records organized by day (`{day}.jsonl`). Activity records represent completed spans of activity — periods where a specific activity type was continuously tracked across one or more recording segments. 586 - 587 - **File path pattern:** 588 - ``` 589 - facets/personal/activities/activities.jsonl # Configured activity types 590 - facets/personal/activities/20260209.jsonl # Completed records for the day 591 - facets/work/activities/20260209.jsonl 592 - facets/work/activities/20260209/coding_095809_303/session_review.md # Generated output 593 - ``` 594 - 595 - Each day file contains one JSON object per line, where each record represents a completed activity span: 596 - 597 - ```jsonl 598 - {"id": "coding_095809_303", "activity": "coding", "segments": ["095809_303", "100313_303", "100816_303", "101320_302"], "level_avg": 0.88, "description": "Developed extraction prompts using Claude Code and VS Code", "active_entities": ["Claude Code", "VS Code", "sunstone"], "created_at": 1770435619415} 599 - {"id": "meeting_090953_303", "activity": "meeting", "segments": ["090953_303", "091457_303", "092001_304", "092506_304", "093010_304"], "level_avg": 1.0, "description": "Sprint planning meeting with the engineering team", "active_entities": ["Alice", "Bob"], "created_at": 1770435619420} 600 - ``` 601 - 602 - #### Record ID scheme 603 - 604 - Activity record IDs follow the format `{activity_type}_{segment_key}` where `segment_key` is the segment in which the activity started. This is unique within a facet+day because only one activity of a given type can start in a given segment for one facet. 605 - 606 - #### Record fields 607 - 608 - - `id` (string) – Unique identifier: `{activity}_{start_segment_key}` (e.g., `coding_095809_303`) 609 - - `activity` (string) – Activity type ID from the facet's configured activities 610 - - `segments` (array of strings) – Ordered list of segment keys where this activity was active 611 - - `level_avg` (float) – Average engagement level across all segments (high=1.0, medium=0.5, low=0.25) 612 - - `description` (string) – AI-synthesized description of the full activity span 613 - - `active_entities` (array of strings) – Merged and deduplicated entity names from all segments 614 - - `created_at` (integer) – Unix timestamp in milliseconds when the record was created 615 - 616 - #### Lifecycle 617 - 618 - Activity records are created by the `activities` segment agent when it detects that an activity has ended: 619 - 620 - 1. The `activity_state` agent tracks per-segment, per-facet activity states with continuity via `since` fields. Each entry includes an `id` field (`{activity}_{since}`) that uniquely identifies the activity span, and `activity.live` events are emitted for active entries. 621 - 2. The `activities` agent runs after `activity_state` and compares previous vs. current segment states 622 - 3. When an activity ends (explicitly, implicitly, or via timeout), the agent walks the segment chain to collect all data 623 - 4. A record is written to the facet's day file with preliminary description 624 - 5. An LLM synthesizes all per-segment descriptions into a unified narrative 625 - 6. The record description is updated with the synthesized version 626 - 627 - **Segment flush:** If no new segments arrive for an extended period (1 hour), the supervisor triggers `sol dream --flush` on the last segment. Agents that declare `hook.flush: true` (like `activities`) run with `flush=True` in their context, treating all remaining active activities as ended. This ensures activities are recorded promptly even when the owner stops working, and prevents cross-day data loss. 628 - 629 - Records are written idempotently — duplicate IDs are skipped on re-runs. 630 - 631 - #### Generated output 632 - 633 - Activity-scheduled agents (`schedule: "activity"`) produce output that is stored alongside the activity records, organized by day and record ID: 634 - 635 - ``` 636 - facets/{facet}/activities/{day}/{activity_id}/{agent}.{ext} 637 - ``` 638 - 639 - For example, a `session_review` agent processing a coding activity would write to: 640 - ``` 641 - facets/work/activities/20260209/coding_095809_303/session_review.md 642 - ``` 643 - 644 - These output directories are only created when activity-scheduled agents run. The path is computed by `get_activity_output_path()` in `think/activities.py` and passed as `output_path` in the agent request. Output files are indexed for search via the `facets/*/activities/*/*/*.md` formatter pattern. 645 - 646 - ## Facet-Scoped Todos 647 - 648 - Todos are organized by facet in `facets/{facet}/todos/{day}.jsonl` where each file stores todo items as JSON Lines. Todos belong to a specific facet (e.g., "personal", "work", "research") and are completely separated by scope. 649 - 650 - **File path pattern:** 651 - ``` 652 - facets/personal/todos/20250110.jsonl 653 - facets/work/todos/20250110.jsonl 654 - facets/research/todos/20250112.jsonl 655 - ``` 656 - 657 - Each file contains one JSON object per line, with the line number (1-indexed) serving as the stable todo ID. 658 - 659 - ```jsonl 660 - {"text": "Draft standup update"} 661 - {"text": "Review PR #1234 for indexing tweaks", "time": "14:30"} 662 - {"text": "Morning planning session notes", "completed": true} 663 - {"text": "Cancel meeting with vendor", "cancelled": true} 664 - ``` 665 - 666 - ### Format Specification 667 - 668 - **JSONL structure:** 669 - 670 - Each line is a JSON object with the following fields: 671 - - `text` (required) – Task description 672 - - `time` (optional) – Scheduled time in `HH:MM` format (e.g., `"14:30"`) 673 - - `completed` (optional) – Set to `true` when task is done 674 - - `cancelled` (optional) – Set to `true` for soft-deleted tasks 675 - - `created_at` (optional) – Unix timestamp in milliseconds when todo was created 676 - - `updated_at` (optional) – Unix timestamp in milliseconds of last modification 677 - 678 - **Facet context:** 679 - - Facet is determined by the file location, not inline tags 680 - - Each facet has its own independent todo list for each day 681 - - Work todos (`facets/work/todos/`) are completely separate from personal todos (`facets/personal/todos/`) 682 - 683 - **Rules:** 684 - - Line number is the stable todo ID (1-indexed); todos are never removed, only cancelled 685 - - Append new todos at the end of the file to maintain stable line numbering 686 - - Mark completed items with `"completed": true` 687 - - Cancel items with `"cancelled": true` (soft delete preserves line numbers) 688 - 689 - **Tool Access:** 690 - All todo operations require both `day` and `facet` parameters: 691 - - `todo_list(day, facet)` – view numbered checklist for a specific facet 692 - - `todo_add(day, facet, text)` – append new todo 693 - - `todo_done(day, facet, line_number)` – mark complete 694 - - `todo_cancel(day, facet, line_number)` – cancel entry (soft delete) 695 - - `todo_upcoming(limit, facet=None)` – view upcoming todos (optionally filtered by facet) 696 - 697 - This facet-scoped structure provides true separation of concerns while enabling automated tools to manage tasks deterministically. 698 - 699 - ## Action Logs 700 - 701 - Action logs record an audit trail of owner-initiated actions and agent tool calls. There are two types: 702 - 703 - - **Journal-level logs** (`config/actions/`) – actions not tied to a specific facet (settings changes, observer management) 704 - - **Facet-scoped logs** (`facets/{facet}/logs/`) – actions within a specific facet (todos, entities) 705 - 706 - ### Journal Action Logs 707 - 708 - The `config/actions/` directory records journal-level actions. Logs are organized by day as `config/actions/YYYYMMDD.jsonl`. 709 - 710 - ```json 711 - { 712 - "timestamp": "2025-12-16T07:33:05.135587+00:00", 713 - "source": "app", 714 - "actor": "settings", 715 - "action": "identity_update", 716 - "params": { 717 - "changed_fields": {"name": {"old": "John", "new": "John Doe"}} 718 - } 719 - } 720 - ``` 721 - 722 - ### Facet Action Logs 723 - 724 - The `logs/` directory within each facet records facet-scoped actions. Logs are organized by day as `facets/{facet}/logs/YYYYMMDD.jsonl`. 725 - 726 - ```json 727 - { 728 - "timestamp": "2025-12-16T07:33:05.135587+00:00", 729 - "source": "tool", 730 - "actor": "todos:todo", 731 - "action": "todo_add", 732 - "params": { 733 - "text": "Review project proposal" 734 - }, 735 - "facet": "work", 736 - "use_id": "1765870373972" 737 - } 738 - ``` 739 - 740 - ### Log Entry Fields 741 - 742 - Both log types share the same structure: 743 - 744 - - `timestamp` – ISO 8601 timestamp of the action 745 - - `source` – Origin type: "app" for web UI, "tool" for agent tools 746 - - `actor` – App or tool name that performed the action 747 - - `action` – Action name (e.g., "todo_add", "identity_update") 748 - - `params` – Action-specific parameters 749 - - `facet` – Facet name (only present in facet-scoped logs) 750 - - `use_id` – Agent ID (only present for agent tool actions) 751 - 752 - These logs enable auditing, debugging, and potential rollback of automated actions. 753 - 754 - ## Token Usage 755 - 756 - The `tokens/` directory tracks token usage from all AI model calls across the system. Usage data is organized by day as `tokens/YYYYMMDD.jsonl` where each file contains JSON Lines entries for that day's API calls. 757 - 758 - ### Token log format 759 - 760 - Each line in a token log file is a JSON object with the following structure: 761 - 762 - ```json 763 - { 764 - "timestamp": 1736812345000, 765 - "model": "gemini-2.5-flash", 766 - "context": "agent.default.20250113_143022", 767 - "segment": "143022_300", 768 - "usage": { 769 - "input_tokens": 1500, 770 - "output_tokens": 500, 771 - "total_tokens": 2000, 772 - "cached_tokens": 800, 773 - "reasoning_tokens": 200 774 - } 775 - } 776 - ``` 777 - 778 - Required fields: 779 - - `timestamp` – Unix timestamp in milliseconds (13 digits) 780 - - `model` – Model identifier (e.g., "gemini-2.5-flash", "gpt-5", "claude-sonnet-4-5") 781 - - `context` – Calling context (e.g., "agent.name.use_id" or "module.function:line") 782 - - `usage` – Token counts dictionary with normalized field names 783 - 784 - Optional fields: 785 - - `segment` – Recording segment key (e.g., "143022_300") when token usage is attributable to a specific observation window 786 - 787 - Usage fields (all optional depending on model capabilities): 788 - - `input_tokens` – Tokens in the prompt/input 789 - - `output_tokens` – Tokens in the response/output 790 - - `total_tokens` – Total tokens consumed 791 - - `cached_tokens` – Tokens served from cache (reduces cost) 792 - - `reasoning_tokens` – Tokens used for extended thinking/reasoning 793 - - `requests` – Number of API requests made (for batch operations) 794 - 795 - The logging system normalizes provider-specific formats (OpenAI, Gemini, Anthropic) into this unified schema for consistent cost tracking and analysis across all models. 796 - 797 - ## Agent Event Logs 798 - 799 - The `talents/` directory stores event logs for all AI talent sessions managed by Cortex. Each talent session produces a JSONL file containing the complete event history. 800 - 801 - **Directory layout:** 802 - - `<name>/` – per-agent subdirectory (e.g., `default/`, `entities--observer/`) 803 - - `<name>/<use_id>_active.jsonl` – currently running agent (renamed when complete) 804 - - `<name>/<use_id>.jsonl` – completed agent session 805 - - `<name>.log` – symlink to the latest completed run for each agent name 806 - - `<day>.jsonl` – day index with one summary line per agent that completed on that day 807 - 808 - The `use_id` is a Unix timestamp in milliseconds that uniquely identifies the session. 809 - 810 - **Event format (JSONL):** 811 - 812 - Each line is a JSON object with an `event` field indicating the event type: 813 - 814 - ```jsonl 815 - {"event": "start", "ts": 1755450767962, "name": "helper", "prompt": "Help me with...", "facet": "work"} 816 - {"event": "text", "ts": 1755450768000, "content": "I'll help you with that."} 817 - {"event": "tool_call", "ts": 1755450769000, "tool": "search", "params": {"query": "example"}} 818 - {"event": "tool_result", "ts": 1755450770000, "tool": "search", "result": "..."} 819 - {"event": "finish", "ts": 1755450771000, "result": "Here's what I found..."} 820 - ``` 821 - 822 - **Common event types:** 823 - - `start` – agent session started, includes name, prompt, and facet 824 - - `text` – streaming text output from the agent 825 - - `tool_call` – agent invoked a tool 826 - - `tool_result` – result returned from tool execution 827 - - `error` – error occurred during execution 828 - - `finish` – agent session completed, includes final result 829 - 830 - See [CORTEX.md](CORTEX.md) for agent architecture and spawning details. 831 - 832 - ## App Storage 833 - 834 - The `apps/` directory provides storage space for Convey apps to persist configuration, data, and artifacts specific to this journal. Each app has its own directory at `apps/<app_name>/` where it can maintain app-specific state independent of the application codebase. 835 - 836 - Apps typically use `config.json` for journal-specific settings and create subdirectories for data storage (e.g., `cache/`, `data/`, `logs/`). This is distinct from the app metadata file (`apps/<app>/app.json` in the codebase) which defines icon, label, and facet support across all journals. See [APPS.md](APPS.md) for storage utilities (`get_app_storage_path`, `load_app_config`, `save_app_config`). 837 - 838 - ## Search Index 839 - 840 - The `indexer/` directory contains the full-text search index built from journal content. 841 - 842 - **Files:** 843 - - `indexer/journal.sqlite` – FTS5 SQLite database containing indexed chunks from agent outputs, events, entities, todos, and action logs 844 - 845 - The indexer converts content to markdown chunks via the formatters framework, then indexes with metadata fields (day, facet, agent) for filtering. Raw audio/screen transcripts are formattable but not indexed — agent outputs provide more useful search results. Use `get_journal_index()` from `think/indexer/journal.py` to access the database programmatically. 846 - 847 - Which content gets indexed is controlled by the `FORMATTERS` registry in `think/formatters.py`. Each entry maps a glob pattern to a formatter function and an `indexed` flag. The registry patterns must be specific enough to use as `Path.glob()` arguments from the journal root — adding a new content location requires a new entry. 848 - 849 - Run `sol indexer` to rebuild the index from current journal content. 850 - 851 - ## Service Health 852 - 853 - The `health/` directory contains log files for long-running services. 854 - 855 - **Files:** 856 - - `health/<service>.log` – log output for each service (e.g., `observe.log`, `cortex.log`, `convey.log`) 857 - - `health/retention.log` – JSONL log of retention purge operations with timestamps, files deleted, bytes freed, and per-segment details 858 - 859 - These logs are useful for debugging service issues. See [DOCTOR.md](DOCTOR.md) for diagnostics and troubleshooting guidance. 860 - 861 - ## Imported Audio 862 - 863 - The `imports/` directory stores audio files imported via the import app, along with their processing artifacts. Each import is organized by detected timestamp: 864 - 865 - ``` 866 - imports/ 867 - └── YYYYMMDD_HHMMSS/ # Import directory (detected or owner-specified timestamp) 868 - ├── import.json # Import metadata and processing status 869 - ├── {original_filename} # Original uploaded audio file 870 - ├── imported.json # Processed transcript in standard format 871 - └── segments.json # List of segment keys created for this import 872 - ``` 873 - 874 - ### Import metadata 875 - 876 - The `import.json` file tracks the import process: 877 - 878 - ```json 879 - { 880 - "original_filename": "meeting_recording.m4a", 881 - "upload_timestamp": 1755034698276, 882 - "upload_datetime": "2025-08-12T15:38:18.276000", 883 - "detection_result": { 884 - "day": "20250630", 885 - "time": "143256", 886 - "confidence": "high", 887 - "source": "Date/Time Original" 888 - }, 889 - "detected_timestamp": "20250630_143256", 890 - "user_timestamp": "20250630_143256", 891 - "file_size": 13950943, 892 - "mime_type": "audio/x-m4a", 893 - "facet": "work", 894 - "processing_completed": "2025-08-12T15:41:42.970189" 895 - } 896 - ``` 897 - 898 - Once processed, imports are linked into the appropriate day's segment via `imported_audio.jsonl` files that reference the original import location. 899 - 900 - ## Day folder contents 901 - 902 - Within each day, captured content is organized into **segments** (timestamped duration folders). The folder name is the **segment key**, which uniquely identifies the segment within the day and follows this format: 903 - 904 - - `HHMMSS_LEN/` – Start time and duration in seconds (e.g., `143022_300/` for a 5-minute segment starting at 14:30:22) 905 - 906 - Each segment progresses through the three-layer pipeline: captures are recorded, extracts are generated, and agent outputs are synthesized. 907 - 908 - #### Stream identity 909 - 910 - Every segment belongs to a **stream** — a named series of segments from a single source. Streams provide navigable chains linking each segment to its predecessor. 911 - 912 - - `stream.json` – Per-segment stream marker containing: 913 - - `stream` – stream name (e.g., `"archon"`, `"import.apple"`) 914 - - `prev_day` – day of the previous segment in this stream (null for first) 915 - - `prev_segment` – segment key of the predecessor (null for first) 916 - - `seq` – sequence number within the stream 917 - 918 - Stream names follow the convention: `{hostname}` for local observers, `{observer_name}` for observers, `import.{type}` for imports (e.g., `import.apple`, `import.text`). Global stream state is tracked in the top-level `streams/` directory as `{name}.json` files. 919 - 920 - Pre-stream segments (created before stream identity was added) have no `stream.json` and are handled gracefully as `None` throughout the pipeline. 921 - 922 - ### Layer 1: Captures 923 - 924 - Captures are the original binary media files recorded by observation tools. 925 - 926 - #### Audio captures 927 - 928 - Audio files are initially written to the day root with the segment key prefix (Linux) or directly to segment folders (macOS): 929 - 930 - - **Linux**: `HHMMSS_LEN_*.flac` – audio files in day root (e.g., `143022_300_audio.flac`) 931 - - **macOS**: `HHMMSS_LEN/audio.m4a` – audio files written directly to segment folder 932 - 933 - After transcription, audio files are moved into their segment folder: 934 - 935 - - `HHMMSS_LEN/*.flac`, `*.m4a`, `*.ogg`, `*.opus`, or `*.wav` – audio files moved here after processing, preserving descriptive suffix (e.g., `audio.flac`, `audio.m4a`, `imported_audio.opus`) 3 + The journal layout and CLI reference moved to [talent/journal/SKILL.md](../talent/journal/SKILL.md). 936 4 937 - Note: The descriptive portion after the segment key (e.g., `_audio`, `_recording`) is preserved when files are moved into segment directories. Processing tools match files by extension only, ignoring the descriptive suffix. 5 + This file is a breadcrumb for old links. 938 6 939 - #### Screen captures 940 - 941 - Screen recordings use per-monitor files with position and connector/displayID in the filename: 942 - 943 - - **Linux**: `HHMMSS_LEN_<position>_<connector>_screen.webm` – screencast video files in day root (e.g., `143022_300_center_DP-3_screen.webm`) 944 - - **macOS**: `HHMMSS_LEN/<position>_<displayID>_screen.mov` – video files written directly to segment folder (e.g., `center_1_screen.mov`) 945 - 946 - After analysis, files are in their segment folder: 947 - 948 - - `HHMMSS_LEN/<position>_<connector>_screen.webm` or `*.mov` – video files (e.g., `center_DP-3_screen.webm`, `center_1_screen.mov`) 949 - 950 - For multi-monitor setups, each monitor produces a separate file. Position labels include: `center`, `left`, `right`, `top`, `bottom`, and combinations like `left-top`. 951 - 952 - ### Layer 2: Extracts 953 - 954 - Extracts are structured data files (JSON/JSONL) derived from captures through AI analysis. 955 - 956 - #### Audio transcript extracts 957 - 958 - The transcript file (`audio.jsonl`) contains a metadata line followed by one JSON object per transcript segment. 959 - 960 - Example transcript file: 961 - 962 - ```jsonl 963 - {"raw": "audio.flac"} 964 - {"start": "00:00:01", "source": "mic", "text": "So we need to finalize the authentication module today."} 965 - {"start": "00:00:15", "source": "sys", "text": "I agree. Let's make sure we have proper unit tests."} 966 - ``` 967 - 968 - **Metadata line (first line):** 969 - - `raw` – path to processed audio file (required) 970 - - `backend` – STT backend used (e.g., "whisper", "revai") 971 - - `model` – model used for transcription (e.g., "medium.en", "revai-fusion") 972 - - `device` – device used for inference (e.g., "cuda", "cpu", "cloud") 973 - - `compute_type` – compute precision used (e.g., "float16", "int8", "api") 974 - - `observer` – observer name if transcribed from an observer source (optional) 975 - - `imported` – object with import metadata for external files (optional): 976 - - `id` – unique import identifier 977 - - `facet` – facet name for entity extraction 978 - - `setting` – contextual setting description 979 - 980 - **Transcript statements (subsequent lines):** 981 - - `start` – timestamp in HH:MM:SS format (required) 982 - - `text` – transcribed text (required) 983 - - `source` – audio source: "mic" or "sys" (optional) 984 - - `speaker` – speaker identifier, numeric or string (optional, not currently populated) 985 - - `corrected` – LLM-corrected version of text (optional, added during enrichment) 986 - - `description` – tone or delivery description, e.g., "enthusiastic", "questioning" (optional, added during enrichment) 987 - 988 - #### Screen frame extracts 989 - 990 - Screen analysis files use per-monitor naming: `<position>_<connector>_screen.jsonl` (e.g., `center_DP-3_screen.jsonl`, `left_HDMI-1_screen.jsonl`). For single-monitor setups, the file is simply `screen.jsonl`. Each file contains one JSON object per qualified frame. Frames qualify when they show significant visual change (≥5% RMS difference) compared to the previous qualified frame. 991 - 992 - Example frame record: 993 - 994 - ```json 995 - { 996 - "frame_id": 123, 997 - "timestamp": 45.67, 998 - "requests": [ 999 - {"type": "describe", "model": "gemini-2.5-flash-lite", "duration": 0.5}, 1000 - {"type": "category", "category": "reading", "model": "gemini-3-flash", "duration": 1.2} 1001 - ], 1002 - "analysis": { 1003 - "visual_description": "Documentation page showing API reference.", 1004 - "primary": "reading", 1005 - "secondary": "none", 1006 - "overlap": true 1007 - }, 1008 - "content": { 1009 - "reading": "# API Reference\n\n## Authentication\n\nUse Bearer tokens..." 1010 - } 1011 - } 1012 - ``` 1013 - 1014 - **Common fields:** 1015 - - `frame_id` – sequential frame number in the video 1016 - - `timestamp` – time in seconds from video start 1017 - - `requests` – list of vision API requests made for this frame (type: "describe" for initial, "category" for follow-ups) 1018 - - `analysis` – categorization result with `primary`, `secondary`, `overlap`, and `visual_description` 1019 - - `content` – object containing category-specific extracted content (see below) 1020 - - `error` – present when processing failed after retries 1021 - 1022 - **Category-specific content (inside `content` object):** 1023 - - `messaging` – markdown content when frame contains chat/email apps 1024 - - `browsing` – markdown content when frame contains web browsing 1025 - - `reading` – markdown content when frame contains documents/articles 1026 - - `productivity` – markdown content when frame contains spreadsheets/slides/calendars 1027 - - `meeting` – JSON object when frame contains video conferencing, includes participant detection and bounding boxes 1028 - 1029 - The vision analysis uses multi-stage conditional processing: 1030 - 1. Initial categorization determines content type (e.g., `code`, `meeting`, `browsing`, `reading`). See `observe/categories/` for the full list of categories. 1031 - 2. Category-specific follow-up prompts are discovered from `observe/categories/*.md` files 1032 - 3. Follow-ups are triggered for categories that have extraction content in their `.md` file (currently: messaging, browsing, reading, productivity output markdown; meeting outputs JSON) 1033 - 1034 - #### Event extracts 1035 - 1036 - Generator output processing extracts time-based events from the day's transcripts—meetings, messages, follow-ups, file activity and more. Events are stored per-facet in JSONL files at `facets/{facet}/events/{day}.jsonl`. 1037 - 1038 - There are two types of events: 1039 - - **Occurrences** – events that happened on the capture day (`occurred: true`) 1040 - - **Anticipations** – future scheduled events extracted from calendar views (`occurred: false`) 1041 - 1042 - ```jsonl 1043 - {"type": "meeting", "start": "09:00:00", "end": "09:30:00", "title": "Team stand-up", "summary": "Status update with the engineering team", "work": true, "participants": ["Jeremie Miller", "Alice", "Bob"], "facet": "work", "agent": "meetings", "occurred": true, "source": "20250101/talents/meetings.md", "details": "Sprint planning discussion"} 1044 - {"type": "deadline", "date": "2025-01-15", "start": null, "end": null, "title": "Project milestone", "summary": "Q1 deliverable due", "work": true, "participants": [], "facet": "work", "agent": "schedule", "occurred": false, "source": "20250101/talents/schedule.md", "details": "Final review before release"} 1045 - ``` 1046 - 1047 - **Common fields:** 1048 - - **type** – event kind: `meeting`, `message`, `file`, `followup`, `documentation`, `research`, `media`, `deadline`, `appointment`, etc. 1049 - - **start** and **end** – HH:MM:SS timestamps (or `null` for anticipations without specific times) 1050 - - **date** – ISO date YYYY-MM-DD (anticipations only, indicates scheduled date) 1051 - - **title** and **summary** – short text for display and search 1052 - - **facet** – facet name the event belongs to (required) 1053 - - **agent** – source generator type (e.g., "meetings", "schedule", "flow") 1054 - - **occurred** – `true` for occurrences, `false` for anticipations 1055 - - **source** – path to the output file that generated this event 1056 - - **work** – boolean, work vs. personal classification 1057 - - **participants** – optional list of people or entities involved 1058 - - **details** – free-form string with additional context 1059 - 1060 - This structure allows the indexer to collect and search events across all facets and days. 1061 - 1062 - ### Layer 3: Agent Outputs 1063 - 1064 - Agent outputs are AI-generated markdown files that provide human-readable narratives synthesized from captures and extracts. 1065 - 1066 - #### Segment outputs 1067 - 1068 - After captures are processed, segment-level outputs are generated within each segment folder as `HHMMSS_LEN/*.md` files. Available segment output types are defined by templates in `talent/` with `"schedule": "segment"` in their metadata JSON. 1069 - 1070 - #### Daily outputs 1071 - 1072 - Post-processing generates day-level outputs in the `talents/` directory that synthesize all segments. 1073 - 1074 - **Generator discovery:** Available generator types are discovered at runtime from: 1075 - - `talent/*.md` – system generator templates (files with `schedule` field but no `tools` field) 1076 - - `apps/{app}/talent/*.md` – app-specific generator templates 1077 - 1078 - Each template is a `.md` file with JSON frontmatter containing metadata (title, description, schedule, output format). The `schedule` field is required and must be `"segment"` or `"daily"` - generators with missing or invalid schedule are skipped. Use `get_talent_configs(has_tools=False)` from `think/talent.py` to retrieve all available generators, or `get_talent_configs(has_tools=False, schedule="daily")` to get generators filtered by schedule. 1079 - 1080 - **Output naming:** 1081 - - System outputs: `talents/{agent}.md` (e.g., `talents/flow.md`, `talents/meetings.md`) 1082 - - App outputs: `talents/_{app}_{agent}.md` (e.g., `talents/_entities_observer.md`) 1083 - - JSON output: `talents/{agent}.json` when metadata specifies `"output": "json"` 1084 - 1085 - Each generator type has a corresponding template file (`{name}.md`) that defines how the AI synthesizes extracts into narrative form. 7 + Start there for the condensed overview, then follow its `references/` links for the full layout and `sol call journal` reference.
+44 -281
talent/journal/SKILL.md
··· 1 1 --- 2 2 name: journal 3 3 description: > 4 - Search and browse journal content across transcripts, insights, events, 5 - entities, and todos. Manage facets, get overviews, and read news feeds. 6 - Use when the owner asks to search, find, or look up journal entries, asks 7 - about a specific day or topic, wants to browse facets, read agent outputs, 8 - or manage facet organization (create, rename, merge, delete). 9 - TRIGGER: search, find, look up, browse, journal, facet, news feed, agent output. 4 + Search, find, list, and show journal data, and explain journal layout, 5 + structure, architecture, storage, facets, and `sol call journal` CLI 6 + commands. Use when the owner asks what a journal is, where content is 7 + stored, to search for meetings, list facets, or show agent output. 10 8 --- 11 9 12 - # Journal CLI Skill 10 + # Journal Skill 13 11 14 - Use these commands to explore journal content from the terminal. 12 + > **First rule for AI agents in a journal**: before doing anything else, run `sol call identity` to hydrate Sol's self, partner, agency, and awareness. The output of that command tells you who you are, who you're working with, and what's currently on your plate. Everything below describes the journal's *layout* — the dynamic identity context comes from the CLI. 15 13 16 - **Environment defaults**: When `SOL_DAY` is set, commands that take a DAY argument will use it automatically. Same for `SOL_SEGMENT` and `SOL_FACET`. 14 + Use this skill for both journal layout questions and `sol call journal` CLI work. 17 15 18 - Common pattern: 16 + ## Overview 19 17 20 - ```bash 21 - sol call journal <command> [args...] 22 - ``` 23 - 24 - **Typical workflow**: `search` to find content across all types → `events` or `facet` for structured detail on a specific day or project. 25 - 26 - ## search 18 + A journal is the on-disk record of captures, extracts, facet data, app storage, and talent outputs. 27 19 28 - ```bash 29 - sol call journal search [QUERY] [-n LIMIT] [--offset N] [-d DAY] [--day-from DAY] [--day-to DAY] [-f FACET] [-a AGENT] 30 20 ``` 31 - 32 - Search the journal index across insights, transcripts, events, entities, and todos. 33 - 34 - - `QUERY`: optional text query. Defaults to empty string (`""`), which works as browse mode when filters are provided. 35 - - `-n, --limit`: max results (default `10`). 36 - - `--offset`: skip N results (default `0`). 37 - - `-d, --day`: exact day filter (`YYYYMMDD`). 38 - - `--day-from`, `--day-to`: inclusive date-range filters (`YYYYMMDD`). 39 - - `-f, --facet`: facet filter (for example `work`, `personal`). 40 - - `-a, --agent`: agent/content filter (for example `flow`, `event`, `news`, `entity:detected`). 41 - 42 - Behavior notes: 43 - 44 - - FTS5 query syntax: 45 - - Terms are `AND`'d by default. 46 - - Use `OR` for alternatives: `apple OR orange`. 47 - - Use quotes for exact phrases: `"weekly sync"`. 48 - - Use `*` for prefix matching: `migrat*`. 49 - - Use either `--day` or date range flags; do not combine exact day with range filters. 50 - 51 - Examples: 52 - 53 - ```bash 54 - sol call journal search "incident review" -n 20 -f work 55 - sol call journal search "standup OR sync" --day-from 20260101 --day-to 20260107 56 - sol call journal search "" -d 20260115 -a audio 21 + ┌──────────────────────┐ 22 + │ LAYER 3: OUTPUTS │ talents/*.md, segment *.md 23 + ├──────────────────────┤ 24 + │ LAYER 2: EXTRACTS │ *.jsonl transcripts, frames, events 25 + ├──────────────────────┤ 26 + │ LAYER 1: CAPTURES │ audio/video files 27 + └──────────────────────┘ 57 28 ``` 58 29 59 - ## events 30 + For the full pipeline, see [captures](references/captures.md). 60 31 61 - ```bash 62 - sol call journal events [DAY] [-f FACET] 63 - ``` 32 + ## Vocabulary 64 33 65 - List structured events for a day. 34 + | Term | Definition | Examples | 35 + |------|------------|----------| 36 + | **Day** | 24-hour activity directory | `20250119/` | 37 + | **Segment** | Timestamped capture window | `143022_300/` | 38 + | **Facet** | Project/context scope | `#work`, `#personal` | 39 + | **Entity** | Tracked person/project/tool | People, companies, tools | 40 + | **Occurrence** | Time-based event | Meetings, messages, files | 66 41 67 - - `DAY`: day in `YYYYMMDD` (default: `SOL_DAY` env). 68 - - `-f, --facet`: optional facet filter. 42 + ## Top-Level Layout 69 43 70 - Use this when you need full event records (titles, summaries, times, participants), not just search snippets. 44 + | Path | Purpose | 45 + |------|---------| 46 + | `chronicle/` | Daily capture folders | 47 + | `entities/` | Journal-level entity records | 48 + | `facets/` | Facet data: entities, todos, events, news, logs | 49 + | `talents/` | Talent run logs and outputs | 50 + | `apps/` | App-specific journal storage | 51 + | `imports/` | Imported audio and artifacts | 52 + | `indexer/` | Search index | 53 + | `config/` | Journal configuration and action logs | 71 54 72 - Examples: 55 + For the full table, see [storage](references/storage.md). 73 56 74 - ```bash 75 - sol call journal events 20260115 76 - sol call journal events 20260115 -f work 77 - ``` 57 + ## References 78 58 79 - ## facet show 80 - 81 - ```bash 82 - sol call journal facet show [NAME] 83 - ``` 84 - 85 - Show a comprehensive facet summary. 86 - 87 - - `NAME`: facet name (default: `SOL_FACET` env). 88 - 89 - Example: 90 - 91 - ```bash 92 - sol call journal facet show work 93 - sol call journal facet show # uses SOL_FACET 94 - ``` 95 - 96 - ## facet create 97 - 98 - ```bash 99 - sol call journal facet create <title> [--emoji EMOJI] [--color COLOR] [--description DESC] [--consent] 100 - ``` 101 - 102 - Create a new facet directory and initial `facet.json`. 103 - 104 - - `title`: display title used for the facet. 105 - - `--emoji`: optional icon emoji (default: `📦`). 106 - - `--color`: optional hex color (default: `#667eea`). 107 - - `--description`: optional description text. 108 - - `--consent`: asserts that the agent has received a direct owner request or explicit owner approval before calling this command. Pass when acting proactively (cogitate, suggestion flows) rather than in direct response to an owner instruction. Adds `"consent": true` to the audit log entry. 109 - 110 - Examples: 111 - 112 - ```bash 113 - sol call journal facet create "Acme Project" 114 - sol call journal facet create "Personal" --emoji "🏠" --color "#ff6f61" --description "Life admin" 115 - ``` 116 - 117 - ## facet update 118 - 119 - ```bash 120 - sol call journal facet update <name> [--title T] [--description D] [--emoji E] [--color C] 121 - ``` 122 - 123 - Update facet metadata fields. 124 - 125 - - `name`: facet identifier. 126 - - `--title`: optional new display title. 127 - - `--description`: optional new description. 128 - - `--emoji`: optional new icon emoji. 129 - - `--color`: optional new hex color. 130 - 131 - Example: 132 - 133 - ```bash 134 - sol call journal facet update work --description "Client work and planning" --emoji "🛠" 135 - ``` 136 - 137 - ## facet rename 138 - 139 - ```bash 140 - sol call journal facet rename <name> <new-name> [--consent] 141 - ``` 142 - 143 - Rename a facet (directory and references in config/chat metadata). 144 - 145 - - `name`: current facet identifier. 146 - - `new-name`: new facet identifier. 147 - - `--consent`: asserts that the agent has received explicit owner approval before performing this structural change. Pass when acting proactively rather than in direct response to an owner instruction. Adds `"consent": true` to the audit log entry. 148 - 149 - Example: 150 - 151 - ```bash 152 - sol call journal facet rename personal personal-life 153 - ``` 154 - 155 - ## facet mute 156 - 157 - ```bash 158 - sol call journal facet mute <name> 159 - ``` 160 - 161 - Hide a facet from default facet listings. 162 - 163 - Example: 164 - 165 - ```bash 166 - sol call journal facet mute personal 167 - ``` 168 - 169 - ## facet unmute 170 - 171 - ```bash 172 - sol call journal facet unmute <name> 173 - ``` 174 - 175 - Show a previously muted facet in default listings again. 176 - 177 - Example: 178 - 179 - ```bash 180 - sol call journal facet unmute personal 181 - ``` 182 - 183 - ## facet delete 184 - 185 - ```bash 186 - sol call journal facet delete <name> [--yes] [--consent] 187 - ``` 188 - 189 - Delete a facet directory and all its data. 190 - 191 - - `--yes`: skip confirmation prompt. 192 - - `--consent`: asserts that the agent has received explicit owner approval before performing this destructive operation. Agents should always pass both `--consent` and `--yes` when calling delete. Adds `"consent": true` to the audit log entry. 193 - 194 - Example: 195 - 196 - ```bash 197 - sol call journal facet delete old-facet 198 - sol call journal facet delete old-facet --yes 199 - ``` 200 - 201 - ## facet merge 202 - 203 - Merge all data from a source facet into a destination facet, then permanently delete the source. 204 - 205 - ```bash 206 - sol call journal facet merge SOURCE --into DEST [--consent] 207 - ``` 208 - 209 - - `SOURCE` — facet to merge from; will be permanently deleted after merge 210 - - `--into DEST` — destination facet to receive all data 211 - - `--consent` — required for agent audit trail when called by an agent 212 - 213 - Moves all entities, open todos (not completed or cancelled), non-cancelled calendar events, and news files from SOURCE into DEST. For entity conflicts (entity exists in both): DEST relationship wins, observations are appended without duplicates. For news conflicts (same date file in both): DEST file is preserved, SOURCE file is skipped. Completed/cancelled todos and cancelled events are not moved (they are deleted with the source facet). After all data is moved, SOURCE is permanently deleted and the index is rebuilt. 214 - 215 - Prints a summary of what will be moved before performing any mutations. 216 - 217 - Example: 218 - 219 - ```bash 220 - sol call journal facet merge old-project --into archive --consent 221 - ``` 222 - 223 - ## facets 224 - 225 - ```bash 226 - sol call journal facets [--all] 227 - ``` 228 - 229 - List available facets. 230 - 231 - - `--all`: include muted facets in the listing. 232 - 233 - ## agents 234 - 235 - ```bash 236 - sol call journal agents [DAY] [-s SEGMENT] 237 - ``` 238 - 239 - List available agent outputs for a day. 240 - 241 - - `DAY`: day in `YYYYMMDD` (default: `SOL_DAY` env). 242 - - `-s, --segment`: optional segment key (default: `SOL_SEGMENT` env). 243 - 244 - Without `--segment`, lists daily agent outputs and per-segment outputs. With `--segment`, lists only that segment's outputs. 245 - 246 - Example: 247 - 248 - ```bash 249 - sol call journal agents 20260115 250 - sol call journal agents -s 091500_300 251 - ``` 252 - 253 - ## read 254 - 255 - ```bash 256 - sol call journal read AGENT [-d DAY] [-s SEGMENT] [--max BYTES] 257 - ``` 258 - 259 - Read full content of an agent output. 260 - 261 - - `AGENT`: agent name, e.g. `flow`, `meetings`, `activity` (positional argument). 262 - - `-d, --day`: day in `YYYYMMDD` (default: `SOL_DAY` env). 263 - - `-s, --segment`: optional segment key (default: `SOL_SEGMENT` env). 264 - - `--max`: max output bytes (default `16384`, `0` for unlimited). 265 - 266 - Without `--segment`, reads from the daily agents directory. With `--segment`, reads from that segment's agents directory. 267 - 268 - Examples: 269 - 270 - ```bash 271 - sol call journal read flow -d 20260115 272 - sol call journal read meetings 273 - sol call journal read activity -s 091500_300 274 - ``` 275 - 276 - ## news 277 - 278 - ```bash 279 - sol call journal news [NAME] [-d DAY] [-n LIMIT] [--cursor CURSOR] [-w] 280 - ``` 281 - 282 - Read or write facet news entries. 283 - 284 - - `NAME`: facet name (default: `SOL_FACET` env). 285 - - `-d, --day`: optional specific day (`YYYYMMDD`, default: `SOL_DAY` env). 286 - - `-n, --limit`: max days to return (default `5`). 287 - - `--cursor`: optional pagination cursor (typically a `YYYYMMDD` cutoff for older entries). 288 - - `-w, --write`: write mode — reads markdown from stdin and saves as news for the given day. 289 - 290 - Behavior notes: 291 - 292 - - Without `--write`: reads and displays existing news entries. Uses `SOL_DAY` to filter to a specific day when set. 293 - - With `--write`: requires `--day` (or `SOL_DAY` env), reads markdown content from stdin, saves to facet news directory. 294 - 295 - Examples: 296 - 297 - ```bash 298 - sol call journal news work -n 3 299 - sol call journal news -d 20260115 # uses SOL_FACET 300 - sol call journal news work --cursor 20260110 -n 5 301 - ``` 59 + - [CLI reference](references/cli.md) — `sol call journal` commands 60 + - [Configuration](references/config.md) — `journal.json`, providers, retention 61 + - [Facets](references/facets.md) — facet folders, entities, news, todos 62 + - [Captures and Extracts](references/captures.md) — layers, imports, segment layout 63 + - [Logs](references/logs.md) — action logs, token usage, talent logs, health 64 + - [Storage](references/storage.md) — top-level layout, app storage, search index
+281
talent/journal/references/captures.md
··· 1 + # Captures and Extracts 2 + 3 + ## The Three-Layer Architecture 4 + 5 + solstone transforms raw recordings into actionable understanding through a three-layer pipeline: 6 + 7 + ``` 8 + ┌─────────────────────────────────────┐ 9 + │ LAYER 3: AGENT OUTPUTS │ Narrative summaries 10 + │ (Markdown files) │ "What it means" 11 + │ - talents/*.md (daily outputs) │ 12 + │ - *.md (segment outputs) │ 13 + └─────────────────────────────────────┘ 14 + ↑ synthesized from 15 + ┌─────────────────────────────────────┐ 16 + │ LAYER 2: EXTRACTS │ Structured data 17 + │ (JSON/JSONL files) │ "What happened" 18 + │ - audio.jsonl, *_audio.jsonl │ 19 + │ - screen.jsonl, *_screen.jsonl │ 20 + │ - events/*.jsonl (per-facet) │ 21 + └─────────────────────────────────────┘ 22 + ↑ derived from 23 + ┌─────────────────────────────────────┐ 24 + │ LAYER 1: CAPTURES │ Raw recordings 25 + │ (Binary media files) │ "What was recorded" 26 + │ - *.flac, *.ogg, *.opus, *.wav (audio) │ 27 + │ - *.webm (video) │ 28 + └─────────────────────────────────────┘ 29 + ``` 30 + 31 + ### Vocabulary Quick Reference 32 + 33 + **Pipeline Layers** 34 + 35 + | Term | Definition | Examples | 36 + |------|------------|----------| 37 + | **Capture** | Raw audio/video recording | `*.flac`, `*.ogg`, `*.opus`, `*.wav`, `*.webm` | 38 + | **Extract** | Structured data from captures | `*.jsonl` | 39 + | **Agent Output** | AI-generated narrative summary | `talents/*.md`, `HHMMSS_LEN/*.md` | 40 + 41 + **Organization** 42 + 43 + | Term | Definition | Examples | 44 + |------|------------|----------| 45 + | **Day** | 24-hour activity directory | `20250119/` | 46 + | **Segment** | 5-minute time window | `143022_300/` (14:30:22, 5 min) | 47 + | **Span** | Sequential segment group | Import creating 3 segments | 48 + | **Facet** | Project/context scope | `#work`, `#personal` | 49 + 50 + **Extracted Data** 51 + 52 + | Term | Definition | Examples | 53 + |------|------------|----------| 54 + | **Entity** | Tracked person/project/concept | People, companies, tools | 55 + | **Occurrence** | Time-based event | Meetings, messages, files | 56 + 57 + ## Imported Audio 58 + 59 + The `imports/` directory stores audio files imported via the import app, along with their processing artifacts. Each import is organized by detected timestamp: 60 + 61 + ``` 62 + imports/ 63 + └── YYYYMMDD_HHMMSS/ # Import directory (detected or owner-specified timestamp) 64 + ├── import.json # Import metadata and processing status 65 + ├── {original_filename} # Original uploaded audio file 66 + ├── imported.json # Processed transcript in standard format 67 + └── segments.json # List of segment keys created for this import 68 + ``` 69 + 70 + ### Import metadata 71 + 72 + The `import.json` file tracks the import process: 73 + 74 + ```json 75 + { 76 + "original_filename": "meeting_recording.m4a", 77 + "upload_timestamp": 1755034698276, 78 + "upload_datetime": "2025-08-12T15:38:18.276000", 79 + "detection_result": { 80 + "day": "20250630", 81 + "time": "143256", 82 + "confidence": "high", 83 + "source": "Date/Time Original" 84 + }, 85 + "detected_timestamp": "20250630_143256", 86 + "user_timestamp": "20250630_143256", 87 + "file_size": 13950943, 88 + "mime_type": "audio/x-m4a", 89 + "facet": "work", 90 + "processing_completed": "2025-08-12T15:41:42.970189" 91 + } 92 + ``` 93 + 94 + Once processed, imports are linked into the appropriate day's segment via `imported_audio.jsonl` files that reference the original import location. 95 + 96 + ## Day folder contents 97 + 98 + Within each day, captured content is organized into **segments** (timestamped duration folders). The folder name is the **segment key**, which uniquely identifies the segment within the day and follows this format: 99 + 100 + - `HHMMSS_LEN/` – Start time and duration in seconds (e.g., `143022_300/` for a 5-minute segment starting at 14:30:22) 101 + 102 + Each segment progresses through the three-layer pipeline: captures are recorded, extracts are generated, and agent outputs are synthesized. 103 + 104 + ### Stream identity 105 + 106 + Every segment belongs to a **stream** — a named series of segments from a single source. Streams provide navigable chains linking each segment to its predecessor. 107 + 108 + - `stream.json` – Per-segment stream marker containing: 109 + - `stream` – stream name (e.g., `"archon"`, `"import.apple"`) 110 + - `prev_day` – day of the previous segment in this stream (null for first) 111 + - `prev_segment` – segment key of the predecessor (null for first) 112 + - `seq` – sequence number within the stream 113 + 114 + Stream names follow the convention: `{hostname}` for local observers, `{observer_name}` for observers, `import.{type}` for imports (e.g., `import.apple`, `import.text`). Global stream state is tracked in the top-level `streams/` directory as `{name}.json` files. 115 + 116 + Pre-stream segments (created before stream identity was added) have no `stream.json` and are handled gracefully as `None` throughout the pipeline. 117 + 118 + ## Layer 1: Captures 119 + 120 + Captures are the original binary media files recorded by observation tools. 121 + 122 + ### Audio captures 123 + 124 + Audio files are initially written to the day root with the segment key prefix (Linux) or directly to segment folders (macOS): 125 + 126 + - **Linux**: `HHMMSS_LEN_*.flac` – audio files in day root (e.g., `143022_300_audio.flac`) 127 + - **macOS**: `HHMMSS_LEN/audio.m4a` – audio files written directly to segment folder 128 + 129 + After transcription, audio files are moved into their segment folder: 130 + 131 + - `HHMMSS_LEN/*.flac`, `*.m4a`, `*.ogg`, `*.opus`, or `*.wav` – audio files moved here after processing, preserving descriptive suffix (e.g., `audio.flac`, `audio.m4a`, `imported_audio.opus`) 132 + 133 + Note: The descriptive portion after the segment key (e.g., `_audio`, `_recording`) is preserved when files are moved into segment directories. Processing tools match files by extension only, ignoring the descriptive suffix. 134 + 135 + ### Screen captures 136 + 137 + Screen recordings use per-monitor files with position and connector/displayID in the filename: 138 + 139 + - **Linux**: `HHMMSS_LEN_<position>_<connector>_screen.webm` – screencast video files in day root (e.g., `143022_300_center_DP-3_screen.webm`) 140 + - **macOS**: `HHMMSS_LEN/<position>_<displayID>_screen.mov` – video files written directly to segment folder (e.g., `center_1_screen.mov`) 141 + 142 + After analysis, files are in their segment folder: 143 + 144 + - `HHMMSS_LEN/<position>_<connector>_screen.webm` or `*.mov` – video files (e.g., `center_DP-3_screen.webm`, `center_1_screen.mov`) 145 + 146 + For multi-monitor setups, each monitor produces a separate file. Position labels include: `center`, `left`, `right`, `top`, `bottom`, and combinations like `left-top`. 147 + 148 + ## Layer 2: Extracts 149 + 150 + Extracts are structured data files (JSON/JSONL) derived from captures through AI analysis. 151 + 152 + ### Audio transcript extracts 153 + 154 + The transcript file (`audio.jsonl`) contains a metadata line followed by one JSON object per transcript segment. 155 + 156 + Example transcript file: 157 + 158 + ```jsonl 159 + {"raw": "audio.flac"} 160 + {"start": "00:00:01", "source": "mic", "text": "So we need to finalize the authentication module today."} 161 + {"start": "00:00:15", "source": "sys", "text": "I agree. Let's make sure we have proper unit tests."} 162 + ``` 163 + 164 + **Metadata line (first line):** 165 + - `raw` – path to processed audio file (required) 166 + - `backend` – STT backend used (e.g., "whisper", "revai") 167 + - `model` – model used for transcription (e.g., "medium.en", "revai-fusion") 168 + - `device` – device used for inference (e.g., "cuda", "cpu", "cloud") 169 + - `compute_type` – compute precision used (e.g., "float16", "int8", "api") 170 + - `observer` – observer name if transcribed from an observer source (optional) 171 + - `imported` – object with import metadata for external files (optional): 172 + - `id` – unique import identifier 173 + - `facet` – facet name for entity extraction 174 + - `setting` – contextual setting description 175 + 176 + **Transcript statements (subsequent lines):** 177 + - `start` – timestamp in HH:MM:SS format (required) 178 + - `text` – transcribed text (required) 179 + - `source` – audio source: "mic" or "sys" (optional) 180 + - `speaker` – speaker identifier, numeric or string (optional, not currently populated) 181 + - `corrected` – LLM-corrected version of text (optional, added during enrichment) 182 + - `description` – tone or delivery description, e.g., "enthusiastic", "questioning" (optional, added during enrichment) 183 + 184 + ### Screen frame extracts 185 + 186 + Screen analysis files use per-monitor naming: `<position>_<connector>_screen.jsonl` (e.g., `center_DP-3_screen.jsonl`, `left_HDMI-1_screen.jsonl`). For single-monitor setups, the file is simply `screen.jsonl`. Each file contains one JSON object per qualified frame. Frames qualify when they show significant visual change (≥5% RMS difference) compared to the previous qualified frame. 187 + 188 + Example frame record: 189 + 190 + ```json 191 + { 192 + "frame_id": 123, 193 + "timestamp": 45.67, 194 + "requests": [ 195 + {"type": "describe", "model": "gemini-2.5-flash-lite", "duration": 0.5}, 196 + {"type": "category", "category": "reading", "model": "gemini-3-flash", "duration": 1.2} 197 + ], 198 + "analysis": { 199 + "visual_description": "Documentation page showing API reference.", 200 + "primary": "reading", 201 + "secondary": "none", 202 + "overlap": true 203 + }, 204 + "content": { 205 + "reading": "# API Reference\n\n## Authentication\n\nUse Bearer tokens..." 206 + } 207 + } 208 + ``` 209 + 210 + **Common fields:** 211 + - `frame_id` – sequential frame number in the video 212 + - `timestamp` – time in seconds from video start 213 + - `requests` – list of vision API requests made for this frame (type: "describe" for initial, "category" for follow-ups) 214 + - `analysis` – categorization result with `primary`, `secondary`, `overlap`, and `visual_description` 215 + - `content` – object containing category-specific extracted content (see below) 216 + - `error` – present when processing failed after retries 217 + 218 + **Category-specific content (inside `content` object):** 219 + - `messaging` – markdown content when frame contains chat/email apps 220 + - `browsing` – markdown content when frame contains web browsing 221 + - `reading` – markdown content when frame contains documents/articles 222 + - `productivity` – markdown content when frame contains spreadsheets/slides/calendars 223 + - `meeting` – JSON object when frame contains video conferencing, includes participant detection and bounding boxes 224 + 225 + The vision analysis uses multi-stage conditional processing: 226 + 1. Initial categorization determines content type (e.g., `code`, `meeting`, `browsing`, `reading`). See `observe/categories/` for the full list of categories. 227 + 2. Category-specific follow-up prompts are discovered from `observe/categories/*.md` files 228 + 3. Follow-ups are triggered for categories that have extraction content in their `.md` file (currently: messaging, browsing, reading, productivity output markdown; meeting outputs JSON) 229 + 230 + ### Event extracts 231 + 232 + Generator output processing extracts time-based events from the day's transcripts—meetings, messages, follow-ups, file activity and more. Events are stored per-facet in JSONL files at `facets/{facet}/events/{day}.jsonl`. 233 + 234 + There are two types of events: 235 + - **Occurrences** – events that happened on the capture day (`occurred: true`) 236 + - **Anticipations** – future scheduled events extracted from calendar views (`occurred: false`) 237 + 238 + ```jsonl 239 + {"type": "meeting", "start": "09:00:00", "end": "09:30:00", "title": "Team stand-up", "summary": "Status update with the engineering team", "work": true, "participants": ["Jeremie Miller", "Alice", "Bob"], "facet": "work", "agent": "meetings", "occurred": true, "source": "20250101/talents/meetings.md", "details": "Sprint planning discussion"} 240 + {"type": "deadline", "date": "2025-01-15", "start": null, "end": null, "title": "Project milestone", "summary": "Q1 deliverable due", "work": true, "participants": [], "facet": "work", "agent": "schedule", "occurred": false, "source": "20250101/talents/schedule.md", "details": "Final review before release"} 241 + ``` 242 + 243 + **Common fields:** 244 + - **type** – event kind: `meeting`, `message`, `file`, `followup`, `documentation`, `research`, `media`, `deadline`, `appointment`, etc. 245 + - **start** and **end** – HH:MM:SS timestamps (or `null` for anticipations without specific times) 246 + - **date** – ISO date YYYY-MM-DD (anticipations only, indicates scheduled date) 247 + - **title** and **summary** – short text for display and search 248 + - **facet** – facet name the event belongs to (required) 249 + - **agent** – source generator type (e.g., "meetings", "schedule", "flow") 250 + - **occurred** – `true` for occurrences, `false` for anticipations 251 + - **source** – path to the output file that generated this event 252 + - **work** – boolean, work vs. personal classification 253 + - **participants** – optional list of people or entities involved 254 + - **details** – free-form string with additional context 255 + 256 + This structure allows the indexer to collect and search events across all facets and days. 257 + 258 + ## Layer 3: Agent Outputs 259 + 260 + Agent outputs are AI-generated markdown files that provide human-readable narratives synthesized from captures and extracts. 261 + 262 + ### Segment outputs 263 + 264 + After captures are processed, segment-level outputs are generated within each segment folder as `HHMMSS_LEN/*.md` files. Available segment output types are defined by templates in `talent/` with `"schedule": "segment"` in their metadata JSON. 265 + 266 + ### Daily outputs 267 + 268 + Post-processing generates day-level outputs in the `talents/` directory that synthesize all segments. 269 + 270 + **Generator discovery:** Available generator types are discovered at runtime from: 271 + - `talent/*.md` – system generator templates (files with `schedule` field but no `tools` field) 272 + - `apps/{app}/talent/*.md` – app-specific generator templates 273 + 274 + Each template is a `.md` file with JSON frontmatter containing metadata (title, description, schedule, output format). The `schedule` field is required and must be `"segment"` or `"daily"` - generators with missing or invalid schedule are skipped. Use `get_talent_configs(has_tools=False)` from `think/talent.py` to retrieve all available generators, or `get_talent_configs(has_tools=False, schedule="daily")` to get generators filtered by schedule. 275 + 276 + **Output naming:** 277 + - System outputs: `talents/{agent}.md` (e.g., `talents/flow.md`, `talents/meetings.md`) 278 + - App outputs: `talents/_{app}_{agent}.md` (e.g., `talents/_entities_observer.md`) 279 + - JSON output: `talents/{agent}.json` when metadata specifies `"output": "json"` 280 + 281 + Each generator type has a corresponding template file (`{name}.md`) that defines how the AI synthesizes extracts into narrative form.
+290
talent/journal/references/cli.md
··· 1 + # Journal CLI Reference 2 + 3 + Use these commands to explore journal content from the terminal. 4 + 5 + **Environment defaults**: When `SOL_DAY` is set, commands that take a DAY argument will use it automatically. Same for `SOL_SEGMENT` and `SOL_FACET`. 6 + 7 + Common pattern: 8 + 9 + ```bash 10 + sol call journal <command> [args...] 11 + ``` 12 + 13 + **Typical workflow**: `search` to find content across all types → `events` or `facet` for structured detail on a specific day or project. 14 + 15 + ## search 16 + 17 + ```bash 18 + sol call journal search [QUERY] [-n LIMIT] [--offset N] [-d DAY] [--day-from DAY] [--day-to DAY] [-f FACET] [-a AGENT] 19 + ``` 20 + 21 + Search the journal index across insights, transcripts, events, entities, and todos. 22 + 23 + - `QUERY`: optional text query. Defaults to empty string (`""`), which works as browse mode when filters are provided. 24 + - `-n, --limit`: max results (default `10`). 25 + - `--offset`: skip N results (default `0`). 26 + - `-d, --day`: exact day filter (`YYYYMMDD`). 27 + - `--day-from`, `--day-to`: inclusive date-range filters (`YYYYMMDD`). 28 + - `-f, --facet`: facet filter (for example `work`, `personal`). 29 + - `-a, --agent`: agent/content filter (for example `flow`, `event`, `news`, `entity:detected`). 30 + 31 + Behavior notes: 32 + 33 + - FTS5 query syntax: 34 + - Terms are `AND`'d by default. 35 + - Use `OR` for alternatives: `apple OR orange`. 36 + - Use quotes for exact phrases: `"weekly sync"`. 37 + - Use `*` for prefix matching: `migrat*`. 38 + - Use either `--day` or date range flags; do not combine exact day with range filters. 39 + 40 + Examples: 41 + 42 + ```bash 43 + sol call journal search "incident review" -n 20 -f work 44 + sol call journal search "standup OR sync" --day-from 20260101 --day-to 20260107 45 + sol call journal search "" -d 20260115 -a audio 46 + ``` 47 + 48 + ## events 49 + 50 + ```bash 51 + sol call journal events [DAY] [-f FACET] 52 + ``` 53 + 54 + List structured events for a day. 55 + 56 + - `DAY`: day in `YYYYMMDD` (default: `SOL_DAY` env). 57 + - `-f, --facet`: optional facet filter. 58 + 59 + Use this when you need full event records (titles, summaries, times, participants), not just search snippets. 60 + 61 + Examples: 62 + 63 + ```bash 64 + sol call journal events 20260115 65 + sol call journal events 20260115 -f work 66 + ``` 67 + 68 + ## facet show 69 + 70 + ```bash 71 + sol call journal facet show [NAME] 72 + ``` 73 + 74 + Show a comprehensive facet summary. 75 + 76 + - `NAME`: facet name (default: `SOL_FACET` env). 77 + 78 + Example: 79 + 80 + ```bash 81 + sol call journal facet show work 82 + sol call journal facet show # uses SOL_FACET 83 + ``` 84 + 85 + ## facet create 86 + 87 + ```bash 88 + sol call journal facet create <title> [--emoji EMOJI] [--color COLOR] [--description DESC] [--consent] 89 + ``` 90 + 91 + Create a new facet directory and initial `facet.json`. 92 + 93 + - `title`: display title used for the facet. 94 + - `--emoji`: optional icon emoji (default: `📦`). 95 + - `--color`: optional hex color (default: `#667eea`). 96 + - `--description`: optional description text. 97 + - `--consent`: asserts that the agent has received a direct owner request or explicit owner approval before calling this command. Pass when acting proactively (cogitate, suggestion flows) rather than in direct response to an owner instruction. Adds `"consent": true` to the audit log entry. 98 + 99 + Examples: 100 + 101 + ```bash 102 + sol call journal facet create "Acme Project" 103 + sol call journal facet create "Personal" --emoji "🏠" --color "#ff6f61" --description "Life admin" 104 + ``` 105 + 106 + ## facet update 107 + 108 + ```bash 109 + sol call journal facet update <name> [--title T] [--description D] [--emoji E] [--color C] 110 + ``` 111 + 112 + Update facet metadata fields. 113 + 114 + - `name`: facet identifier. 115 + - `--title`: optional new display title. 116 + - `--description`: optional new description. 117 + - `--emoji`: optional new icon emoji. 118 + - `--color`: optional new hex color. 119 + 120 + Example: 121 + 122 + ```bash 123 + sol call journal facet update work --description "Client work and planning" --emoji "🛠" 124 + ``` 125 + 126 + ## facet rename 127 + 128 + ```bash 129 + sol call journal facet rename <name> <new-name> [--consent] 130 + ``` 131 + 132 + Rename a facet (directory and references in config/chat metadata). 133 + 134 + - `name`: current facet identifier. 135 + - `new-name`: new facet identifier. 136 + - `--consent`: asserts that the agent has received explicit owner approval before performing this structural change. Pass when acting proactively rather than in direct response to an owner instruction. Adds `"consent": true` to the audit log entry. 137 + 138 + Example: 139 + 140 + ```bash 141 + sol call journal facet rename personal personal-life 142 + ``` 143 + 144 + ## facet mute 145 + 146 + ```bash 147 + sol call journal facet mute <name> 148 + ``` 149 + 150 + Hide a facet from default facet listings. 151 + 152 + Example: 153 + 154 + ```bash 155 + sol call journal facet mute personal 156 + ``` 157 + 158 + ## facet unmute 159 + 160 + ```bash 161 + sol call journal facet unmute <name> 162 + ``` 163 + 164 + Show a previously muted facet in default listings again. 165 + 166 + Example: 167 + 168 + ```bash 169 + sol call journal facet unmute personal 170 + ``` 171 + 172 + ## facet delete 173 + 174 + ```bash 175 + sol call journal facet delete <name> [--yes] [--consent] 176 + ``` 177 + 178 + Delete a facet directory and all its data. 179 + 180 + - `--yes`: skip confirmation prompt. 181 + - `--consent`: asserts that the agent has received explicit owner approval before performing this destructive operation. Agents should always pass both `--consent` and `--yes` when calling delete. Adds `"consent": true` to the audit log entry. 182 + 183 + Example: 184 + 185 + ```bash 186 + sol call journal facet delete old-facet 187 + sol call journal facet delete old-facet --yes 188 + ``` 189 + 190 + ## facet merge 191 + 192 + Merge all data from a source facet into a destination facet, then permanently delete the source. 193 + 194 + ```bash 195 + sol call journal facet merge SOURCE --into DEST [--consent] 196 + ``` 197 + 198 + - `SOURCE` — facet to merge from; will be permanently deleted after merge 199 + - `--into DEST` — destination facet to receive all data 200 + - `--consent` — required for agent audit trail when called by an agent 201 + 202 + Moves all entities, open todos (not completed or cancelled), non-cancelled calendar events, and news files from SOURCE into DEST. For entity conflicts (entity exists in both): DEST relationship wins, observations are appended without duplicates. For news conflicts (same date file in both): DEST file is preserved, SOURCE file is skipped. Completed/cancelled todos and cancelled events are not moved (they are deleted with the source facet). After all data is moved, SOURCE is permanently deleted and the index is rebuilt. 203 + 204 + Prints a summary of what will be moved before performing any mutations. 205 + 206 + Example: 207 + 208 + ```bash 209 + sol call journal facet merge old-project --into archive --consent 210 + ``` 211 + 212 + ## facets 213 + 214 + ```bash 215 + sol call journal facets [--all] 216 + ``` 217 + 218 + List available facets. 219 + 220 + - `--all`: include muted facets in the listing. 221 + 222 + ## agents 223 + 224 + ```bash 225 + sol call journal agents [DAY] [-s SEGMENT] 226 + ``` 227 + 228 + List available agent outputs for a day. 229 + 230 + - `DAY`: day in `YYYYMMDD` (default: `SOL_DAY` env). 231 + - `-s, --segment`: optional segment key (default: `SOL_SEGMENT` env). 232 + 233 + Without `--segment`, lists daily agent outputs and per-segment outputs. With `--segment`, lists only that segment's outputs. 234 + 235 + Example: 236 + 237 + ```bash 238 + sol call journal agents 20260115 239 + sol call journal agents -s 091500_300 240 + ``` 241 + 242 + ## read 243 + 244 + ```bash 245 + sol call journal read AGENT [-d DAY] [-s SEGMENT] [--max BYTES] 246 + ``` 247 + 248 + Read full content of an agent output. 249 + 250 + - `AGENT`: agent name, e.g. `flow`, `meetings`, `activity` (positional argument). 251 + - `-d, --day`: day in `YYYYMMDD` (default: `SOL_DAY` env). 252 + - `-s, --segment`: optional segment key (default: `SOL_SEGMENT` env). 253 + - `--max`: max output bytes (default `16384`, `0` for unlimited). 254 + 255 + Without `--segment`, reads from the daily agents directory. With `--segment`, reads from that segment's agents directory. 256 + 257 + Examples: 258 + 259 + ```bash 260 + sol call journal read flow -d 20260115 261 + sol call journal read meetings 262 + sol call journal read activity -s 091500_300 263 + ``` 264 + 265 + ## news 266 + 267 + ```bash 268 + sol call journal news [NAME] [-d DAY] [-n LIMIT] [--cursor CURSOR] [-w] 269 + ``` 270 + 271 + Read or write facet news entries. 272 + 273 + - `NAME`: facet name (default: `SOL_FACET` env). 274 + - `-d, --day`: optional specific day (`YYYYMMDD`, default: `SOL_DAY` env). 275 + - `-n, --limit`: max days to return (default `5`). 276 + - `--cursor`: optional pagination cursor (typically a `YYYYMMDD` cutoff for older entries). 277 + - `-w, --write`: write mode — reads markdown from stdin and saves as news for the given day. 278 + 279 + Behavior notes: 280 + 281 + - Without `--write`: reads and displays existing news entries. Uses `SOL_DAY` to filter to a specific day when set. 282 + - With `--write`: requires `--day` (or `SOL_DAY` env), reads markdown content from stdin, saves to facet news directory. 283 + 284 + Examples: 285 + 286 + ```bash 287 + sol call journal news work -n 3 288 + sol call journal news -d 20260115 # uses SOL_FACET 289 + sol call journal news work --cursor 20260110 -n 5 290 + ```
+311
talent/journal/references/config.md
··· 1 + # Configuration 2 + 3 + The optional `config/journal.json` file allows customization of journal processing and presentation based on owner preferences. This file should be created at the journal root and contains personal settings that affect how the system processes and interprets journal data. 4 + 5 + ## Identity configuration 6 + 7 + The `identity` block contains information about the journal owner that helps tools correctly identify the owner in transcripts, meetings, and other captured content: 8 + 9 + ```json 10 + { 11 + "identity": { 12 + "name": "Jeremie Miller", 13 + "preferred": "Jer", 14 + "pronouns": { 15 + "subject": "he", 16 + "object": "him", 17 + "possessive": "his", 18 + "reflexive": "himself" 19 + }, 20 + "aliases": ["Jer", "jeremie"], 21 + "email_addresses": ["jer@example.com"], 22 + "timezone": "America/Los_Angeles" 23 + } 24 + } 25 + ``` 26 + 27 + Fields: 28 + - `name` (string) – Full legal or formal name of the journal owner 29 + - `preferred` (string) – Preferred name or nickname to be used when addressing the owner 30 + - `pronouns` (object) – Structured pronoun set for template usage with fields: 31 + - `subject` – Subject pronoun (e.g., "he", "she", "they") 32 + - `object` – Object pronoun (e.g., "him", "her", "them") 33 + - `possessive` – Possessive adjective (e.g., "his", "her", "their") 34 + - `reflexive` – Reflexive pronoun (e.g., "himself", "herself", "themselves") 35 + - `aliases` (array of strings) – Alternative names, nicknames, or usernames that may appear in transcripts 36 + - `email_addresses` (array of strings) – Email addresses associated with the owner for participant detection 37 + - `timezone` (string) – IANA timezone identifier (e.g., "America/New_York", "Europe/London") for timestamp interpretation 38 + 39 + This configuration helps meeting extraction identify the owner as a participant, enables personalized agent interactions, and ensures timestamps are interpreted correctly across the journal. 40 + 41 + ## Convey configuration 42 + 43 + The `convey` block contains settings for the web application: 44 + 45 + ```json 46 + { 47 + "convey": { 48 + "password_hash": "<set via sol password set>" 49 + } 50 + } 51 + ``` 52 + 53 + Fields: 54 + - `password_hash` (string) – Hashed password for accessing the convey web application. Set via `sol password set`. 55 + 56 + **UI Preferences:** The separate `config/convey.json` file stores UI/UX personalization (facet/app ordering, selected facet). All fields optional: 57 + 58 + ```json 59 + { 60 + "facets": {"order": ["work", "personal"], "selected": "work"}, 61 + "apps": {"order": ["home", "calendar", "todos"], "starred": ["home", "todos"]} 62 + } 63 + ``` 64 + 65 + - `facets.order` – Custom facet ordering. `facets.selected` – Currently selected facet (auto-synced with browser). 66 + - `apps.order` – Custom app ordering in menu bar. 67 + - `apps.starred` – Apps to show in the quick-access starred section. 68 + 69 + ## Retention configuration 70 + 71 + The `retention` block controls automatic cleanup of layer 1 raw media (audio recordings, video captures, screen diffs) while preserving all layer 2 extracts and layer 3 agent outputs. Three modes control when raw media is deleted: 72 + 73 + - `"keep"` – retain raw media indefinitely 74 + - `"days"` – delete raw media after `raw_media_days` days, once the segment has finished processing (default: 7 days) 75 + - `"processed"` – delete raw media as soon as the segment has finished processing 76 + 77 + ```json 78 + { 79 + "retention": { 80 + "raw_media": "days", 81 + "raw_media_days": 30, 82 + "per_stream": { 83 + "plaud": { 84 + "raw_media": "days", 85 + "raw_media_days": 7 86 + }, 87 + "archon": { 88 + "raw_media": "processed" 89 + } 90 + } 91 + } 92 + } 93 + ``` 94 + 95 + Fields: 96 + - `raw_media` (string) – Retention mode: `"keep"`, `"days"`, or `"processed"`. Default: `"days"`. 97 + - `raw_media_days` (integer or null) – Number of days to retain raw media when mode is `"days"`. Default: `7`. Required when `raw_media` is `"days"`, ignored otherwise. 98 + - `per_stream` (object) – Per-stream overrides keyed by stream name. Each entry supports `raw_media` and `raw_media_days`. Omitted fields inherit from the global retention settings. 99 + 100 + "Raw media" means layer 1 capture files only: audio files (`.flac`, `.opus`, `.ogg`, `.m4a`, `.wav`), video files (`.webm`, `.mov`, `.mp4`), and screen diffs (`monitor_*_diff.png`). 101 + 102 + All layer 2 and layer 3 content is always preserved regardless of retention policy: transcripts (`audio.jsonl`, `screen.jsonl`), talent outputs (`talents/*.md`), speaker labels (`talents/speaker_labels.json`), facet events (`events/*.jsonl`), entity data, segment metadata (`stream.json`), and search index entries. 103 + 104 + Raw media is never deleted from segments that haven't finished processing. A segment is considered complete only when all four checks pass: 105 + 106 + - No `_active.jsonl` files in `talents/` (no running talents) 107 + - `audio.jsonl` (or `*_audio.jsonl`) exists if audio raw media was captured 108 + - `screen.jsonl` (or `*_screen.jsonl`) exists if video raw media was captured 109 + - `talents/speaker_labels.json` exists if voice embeddings (`.npz`) are present 110 + 111 + Purged segments remain fully navigable in convey. Transcripts, entities, speaker labels, and summaries are all intact. The only difference is that audio/video playback is unavailable. 112 + 113 + ## Environment variables 114 + 115 + The `env` block provides fallback values for environment variables. These are loaded at CLI startup and used when the corresponding variable is not set in the shell or `.env` file: 116 + 117 + ```json 118 + { 119 + "env": { 120 + "GOOGLE_API_KEY": "your-google-api-key", 121 + "ANTHROPIC_API_KEY": "your-anthropic-api-key", 122 + "OPENAI_API_KEY": "your-openai-api-key", 123 + "REVAI_ACCESS_TOKEN": "your-revai-token", 124 + "PLAUD_ACCESS_TOKEN": "your-plaud-token" 125 + } 126 + } 127 + ``` 128 + 129 + **Precedence order** (highest to lowest): 130 + 1. Shell environment variables 131 + 2. `.env` file in project root 132 + 3. Journal config `env` section 133 + 134 + This allows storing API keys in the journal config as an alternative to `.env`, which can be useful when the journal is synced across machines or when you want to keep all configuration in one place. 135 + 136 + ### Template usage examples 137 + 138 + The structured pronoun format enables proper pronoun usage in generated text and agent responses: 139 + 140 + ```python 141 + # In templates or generated text: 142 + f"{identity.pronouns.subject} joined the meeting" # "he joined the meeting" 143 + f"I spoke with {identity.pronouns.object}" # "I spoke with him" 144 + f"That is {identity.pronouns.possessive} desk" # "That is his desk" 145 + f"{identity.pronouns.subject} did it {identity.pronouns.reflexive}" # "he did it himself" 146 + ``` 147 + 148 + For complete documentation of the prompt template system including all variable categories, composition patterns, and how to add new variables, see [PROMPT_TEMPLATES.md](../../../docs/PROMPT_TEMPLATES.md). 149 + 150 + ## Transcribe configuration 151 + 152 + The `transcribe` block configures audio transcription settings for `sol transcribe`: 153 + 154 + ```json 155 + { 156 + "transcribe": { 157 + "backend": "whisper", 158 + "enrich": true, 159 + "preserve_all": false, 160 + "noise_upgrade_min_speech_ratio": 0.3, 161 + "whisper": { 162 + "device": "auto", 163 + "model": "medium.en", 164 + "compute_type": "default" 165 + }, 166 + "revai": { 167 + "model": "fusion" 168 + } 169 + } 170 + } 171 + ``` 172 + 173 + **Top-level fields:** 174 + - `backend` (string) – STT backend to use: `"whisper"` (local processing) or `"revai"` (cloud with speaker diarization). Default: `"whisper"`. 175 + - `enrich` (boolean) – Enable LLM enrichment for topic extraction and transcript correction. Default: `true`. 176 + - `preserve_all` (boolean) – Keep audio files even when no speech is detected. When `false`, silent recordings are deleted to save disk space. Default: `false`. 177 + - `noise_upgrade_min_speech_ratio` (number) – Min speech/loud ratio required for noisy upgrade (default: `0.3`). Filters out music and other non-speech noise. 178 + 179 + **Whisper backend settings** (`transcribe.whisper`): 180 + - `device` (string) – Device for inference: `"auto"` (detect GPU, fall back to CPU), `"cpu"`, or `"cuda"`. Default: `"auto"`. 181 + - `model` (string) – Whisper model to use (e.g., `"tiny.en"`, `"base.en"`, `"small.en"`, `"medium.en"`, `"large-v3-turbo"`, `"distil-large-v3"`). Default: `"medium.en"`. 182 + - `compute_type` (string) – Compute precision: `"default"` (auto-select optimal for platform), `"float32"` (most compatible), `"float16"` (faster on CUDA GPUs), `"int8"` (fastest on CPU). Default: `"default"`. 183 + 184 + **Rev.ai backend settings** (`transcribe.revai`): 185 + - `model` (string) – Rev.ai transcriber model: `"fusion"` (best quality), `"machine"` (fast automated), or `"low_cost"`. Default: `"fusion"`. 186 + 187 + **Platform auto-detection** (Whisper): When `compute_type` is `"default"`, optimal settings are automatically selected: 188 + - **CUDA GPU**: Uses `float16` for GPU-optimized inference 189 + - **CPU (including Apple Silicon)**: Uses `int8` for ~2x faster inference and significantly faster model loading 190 + 191 + Voice embeddings (resemblyzer) also auto-detect the best device: MPS on Apple Silicon (~16x faster), CUDA when available, or CPU fallback. 192 + 193 + CLI flags can override settings: `--backend` selects the backend, `--cpu` forces CPU mode with int8 (Whisper only), `--model MODEL` overrides the Whisper model. 194 + 195 + ## Describe configuration 196 + 197 + The `describe` block configures screen analysis settings for `sol describe`: 198 + 199 + ```json 200 + { 201 + "describe": { 202 + "max_extractions": 20, 203 + "categories": { 204 + "code": { 205 + "importance": "high", 206 + "extraction": "Extract when viewing different repositories or files" 207 + }, 208 + "gaming": { 209 + "importance": "ignore" 210 + } 211 + } 212 + } 213 + } 214 + ``` 215 + 216 + **Fields:** 217 + - `max_extractions` (integer) – Maximum number of frames to run detailed content extraction on per video. The first qualified frame is always extracted regardless of this limit. When more frames are eligible, selection uses AI-based prioritization (falling back to random selection). Default: `20`. 218 + - `categories` (object) – Per-category overrides for importance and extraction guidance. 219 + 220 + ### Category overrides 221 + 222 + Each category (e.g., `code`, `meeting`, `browsing`) can have: 223 + 224 + | Field | Values | Description | 225 + |-------|--------|-------------| 226 + | `importance` | `high`, `normal`, `low`, `ignore` | Advisory priority hint for AI frame selection. `high` prioritizes these frames, `low` deprioritizes unless unique, `ignore` suggests skipping unless categorization seems wrong. Default: `normal`. | 227 + | `extraction` | string | Custom guidance for when to extract content from this category. Overrides the default from the category's `.json` file. | 228 + 229 + Importance levels are advisory hints passed to the AI selection process, not hard filters. The AI may still select frames from `ignore` categories if it determines the content is valuable or the categorization may be incorrect. 230 + 231 + ## Providers configuration 232 + 233 + The `providers` block enables fine-grained control over which LLM provider and model is used for different contexts. This supports a tier-based system where you can specify capability levels (pro/flash/lite) rather than specific model names. 234 + 235 + ```json 236 + { 237 + "providers": { 238 + "default": { 239 + "provider": "google", 240 + "tier": 2 241 + }, 242 + "contexts": { 243 + "observe.*": {"provider": "google", "tier": 3}, 244 + "talent.system.*": {"tier": 1}, 245 + "talent.system.meetings": {"provider": "anthropic", "disabled": true}, 246 + "talent.entities.observer": {"tier": 2, "extract": false} 247 + }, 248 + "models": { 249 + "google": { 250 + "1": "gemini-3-pro-preview", 251 + "2": "gemini-3-flash-preview", 252 + "3": "gemini-2.5-flash-lite" 253 + } 254 + } 255 + } 256 + } 257 + ``` 258 + 259 + ### Tier system 260 + 261 + Tiers provide a provider-agnostic way to specify model capability levels: 262 + 263 + | Tier | Name | Description | 264 + |------|-------|-------------| 265 + | 1 | pro | Highest capability, best for complex reasoning | 266 + | 2 | flash | Balanced performance and cost (default) | 267 + | 3 | lite | Fastest and cheapest, for simple tasks | 268 + 269 + System defaults map tiers to models for each provider. See `think/models.py` for current tier-to-model mappings (`PROVIDER_DEFAULTS` constant). 270 + 271 + If a requested tier is unavailable for a provider, the system falls back to more capable tiers (e.g., tier 3 → tier 2 → tier 1). 272 + 273 + ### Context matching 274 + 275 + Contexts are matched in order of specificity: 276 + 1. **Exact match** – `"talent.system.meetings"` matches only that exact context 277 + 2. **Glob pattern** – `"observe.*"` matches any context starting with `observe.` 278 + 3. **Default** – Falls back to the `default` configuration 279 + 280 + ### Context naming convention 281 + 282 + Talent configs (agents and generators) use the pattern `talent.{source}.{name}`: 283 + - System configs: `talent.system.{name}` (e.g., `talent.system.meetings`, `talent.system.default`) 284 + - App configs: `talent.{app}.{name}` (e.g., `talent.entities.observer`, `talent.support.support`) 285 + 286 + Other contexts follow the pattern `{module}.{feature}[.{operation}]`: 287 + - Observe pipeline: `observe.describe.frame`, `observe.enrich`, `observe.transcribe.gemini` 288 + 289 + ### Configuration options 290 + 291 + **default** – Global defaults applied when no context matches: 292 + - `provider` (string) – Provider name: `"google"`, `"openai"`, or `"anthropic"`. Default: `"google"`. 293 + - `tier` (integer) – Tier number (1-3). Default: `2` (flash). 294 + - `model` (string) – Explicit model name (overrides tier if specified). 295 + 296 + **contexts** – Context-specific overrides. Each key is a context pattern, value is: 297 + - `provider` (string) – Override provider (optional, inherits from default). 298 + - `tier` (integer) – Tier number (optional). 299 + - `model` (string) – Explicit model name (optional, overrides tier). 300 + - `disabled` (boolean) – Disable this talent config (optional, talent contexts only). 301 + - `extract` (boolean) – Enable/disable event extraction for generators with occurrence/anticipation hooks (optional). 302 + 303 + **models** – Per-provider tier overrides. Maps provider name to tier-model mappings: 304 + ```json 305 + { 306 + "google": {"1": "gemini-3-pro-preview", "2": "gemini-3-flash-preview"}, 307 + "openai": {"2": "gpt-5-mini-custom"} 308 + } 309 + ``` 310 + 311 + Note: Tier keys in JSON must be strings (`"1"`, `"2"`, `"3"`) since JSON doesn't support integer keys.
+298
talent/journal/references/facets.md
··· 1 + # Facets 2 + 3 + The `facets/` directory provides a way to organize journal content by scope or focus area. Each facet represents a cohesive grouping of related activities, projects, or areas of interest. 4 + 5 + ## Facet structure 6 + 7 + Each facet is organized as `facets/<facet>/` where `<facet>` is a descriptive short unique name. When referencing facets in the system, use hashtags (e.g., `#personal` for the "Personal Life" facet, `#ml_research` for "Machine Learning Research"). Each facet folder contains: 8 + 9 + - `facet.json` – metadata file with facet title and description. 10 + - `activities/` – configured activities and completed activity records (see [activity records](#activity-records)). 11 + - `entities/` – entity relationships and detected entities (see [facet entities](#facet-entities)). 12 + - `todos/` – daily todo lists (see [facet-scoped todos](#facet-scoped-todos)). 13 + - `events/` – extracted events per day (see [event extracts](captures.md#event-extracts)). 14 + - `news/` – daily news and updates relevant to the facet (optional). 15 + - `logs/` – action audit logs for tool calls (optional, see [action logs](logs.md#action-logs)). 16 + 17 + ## Facet metadata 18 + 19 + The `facet.json` file contains basic information about the facet: 20 + 21 + ```json 22 + { 23 + "title": "Machine Learning Research", 24 + "description": "AI/ML research projects, experiments, and related activities", 25 + "color": "#4f46e5", 26 + "emoji": "🧠" 27 + } 28 + ``` 29 + 30 + Optional fields: 31 + - `color` – hex color code for the facet card background in the web UI 32 + - `emoji` – emoji icon displayed in the top-left of the facet card 33 + - `muted` – boolean flag to mute/hide the facet from views (default: false) 34 + - Muted facets are filtered out by `get_enabled_facets()`, so agents that iterate enabled facets, such as `entity_observer`, skip them silently. 35 + 36 + ## Facet Entities 37 + 38 + Entities in solstone use a two-tier architecture with **journal-level entities** (canonical identity) and **facet relationships** (per-facet context). There are also **detected entities** (daily discoveries) that can be promoted to attached status. 39 + 40 + ### Entity Storage Structure 41 + 42 + ``` 43 + entities/ 44 + └── {entity_id}/ 45 + └── entity.json # Journal-level entity (canonical identity) 46 + 47 + facets/{facet}/ 48 + └── entities/ 49 + ├── YYYYMMDD.jsonl # Daily detected entities 50 + └── {entity_id}/ 51 + ├── entity.json # Facet relationship 52 + ├── observations.jsonl # Durable facts (optional) 53 + └── voiceprints.npz # Voice recognition data (optional) 54 + ``` 55 + 56 + **Journal-level entities** (`entities/<id>/entity.json`) store the canonical identity: name, type, aliases (aka), and principal flag. These are shared across all facets. 57 + 58 + **Facet relationships** (`facets/<facet>/entities/<id>/entity.json`) store per-facet context: description, timestamps, and custom fields specific to that facet. 59 + 60 + **Entity memory** (observations, voiceprints) is stored alongside facet relationships. 61 + 62 + ### Journal-Level Entities 63 + 64 + Journal entities represent the canonical identity record: 65 + 66 + ```json 67 + { 68 + "id": "alice_johnson", 69 + "name": "Alice Johnson", 70 + "type": "Person", 71 + "aka": ["Ali", "AJ"], 72 + "is_principal": false, 73 + "created_at": 1704067200000 74 + } 75 + ``` 76 + 77 + **Standard fields:** 78 + - `id` (string) – Stable slug identifier derived from name via `entity_slug()` in `think/entities/` (lowercase, underscores, e.g., "Alice Johnson" → "alice_johnson"). Used for folder paths, URLs, and tool references. 79 + - `name` (string) – Display name for the entity. 80 + - `type` (string) – Entity type (e.g., "Person", "Company", "Project", "Tool"). Types are flexible and owner-defined; must be alphanumeric with spaces, minimum 3 characters. 81 + - `aka` (array of strings) – Alternative names, nicknames, or acronyms. Used in audio transcription and fuzzy matching. 82 + - `is_principal` (boolean) – When `true`, identifies this entity as the journal owner. Auto-flagged when name/aka matches identity config. 83 + - `blocked` (boolean) – When `true`, entity is hidden from all facets and excluded from agent context. 84 + - `created_at` (integer) – Unix timestamp in milliseconds when entity was created. 85 + 86 + ### Facet Relationships 87 + 88 + Facet relationships link journal entities to specific facets with context: 89 + 90 + ```json 91 + { 92 + "entity_id": "alice_johnson", 93 + "description": "Lead engineer on the API project", 94 + "attached_at": 1704067200000, 95 + "updated_at": 1704153600000, 96 + "last_seen": "20260115" 97 + } 98 + ``` 99 + 100 + **Relationship fields:** 101 + - `entity_id` (string) – Links to the journal entity. 102 + - `description` (string) – Facet-specific description. 103 + - `attached_at` (integer) – Unix timestamp when attached to this facet. 104 + - `updated_at` (integer) – Unix timestamp of last modification. 105 + - `last_seen` (string) – Day (YYYYMMDD) when last mentioned in journal content. 106 + - `detached` (boolean) – When `true`, soft-deleted from this facet but data preserved. 107 + - Custom fields (any) – Additional facet-specific metadata (e.g., `tier`, `status`, `priority`). 108 + 109 + ### Detected Entities 110 + 111 + Daily detection files (`facets/<facet>/entities/YYYYMMDD.jsonl`) contain entities automatically discovered by agents from journal content: 112 + 113 + ```jsonl 114 + {"type": "Person", "name": "Charlie Brown", "description": "Mentioned in standup meeting"} 115 + {"type": "Tool", "name": "React", "description": "Used in UI development work"} 116 + ``` 117 + 118 + ### Entity Lifecycle 119 + 120 + 1. **Detection**: Daily agents scan journal content and record entities in `facets/<facet>/entities/YYYYMMDD.jsonl` 121 + 2. **Aggregation**: Review agent tracks detection frequency across recent days 122 + 3. **Promotion**: Entities with 3+ detections are auto-promoted to attached, or owners manually promote via UI 123 + 4. **Persistence**: Creates journal entity + facet relationship; remains active until detached 124 + 5. **Detachment**: Sets `detached: true` on facet relationship, preserving all data 125 + 6. **Re-attachment**: Clears detached flag, restoring the entity with preserved history 126 + 7. **Blocking**: Sets `blocked: true` on journal entity and detaches from all facets 127 + 128 + ### Cross-Facet Behavior 129 + 130 + The same entity can be attached to multiple facets with independent descriptions and timestamps. When loading entities across all facets, the alphabetically-first facet wins for duplicates during aggregation. 131 + 132 + ## Facet News 133 + 134 + The `news/` directory provides a chronological record of news, updates, and external developments relevant to the facet. This allows tracking of industry news, research updates, regulatory changes, or any external information that impacts the facet's focus area. 135 + 136 + ### News organization 137 + 138 + News files are organized by date as `news/YYYYMMDD.md` where each file contains the day's relevant news items. Only create files for days that have news to record—sparse population is expected. 139 + 140 + ### News file format 141 + 142 + Each `YYYYMMDD.md` file is a markdown document with a consistent structure: 143 + 144 + ```markdown 145 + # 2025-01-18 News - Machine Learning Research 146 + 147 + ## OpenAI Announces New Model Architecture 148 + **Source:** techcrunch.com | **Time:** 09:15 149 + Summary of the announcement and its relevance to current research projects... 150 + 151 + ## Paper: "Efficient Attention Mechanisms in Transformers" 152 + **Source:** arxiv.org | **Time:** 14:30 153 + Key findings from the paper and potential applications... 154 + 155 + ## Google Research Updates Dataset License Terms 156 + **Source:** blog.google | **Time:** 16:45 157 + Changes to dataset licensing that may affect ongoing experiments... 158 + ``` 159 + 160 + ### News entry structure 161 + 162 + Each news entry should include: 163 + - **Title** – concise headline as a level 2 heading 164 + - **Source** – origin of the news (website, journal, etc.) 165 + - **Time** – optional time of publication or discovery (HH:MM format) 166 + - **Summary** – brief description focusing on relevance to the facet 167 + - **Impact** – optional notes on how this affects facet work 168 + 169 + ### News metadata 170 + 171 + Optionally, a `news.json` file can be maintained at the root of the news directory to track metadata: 172 + 173 + ```json 174 + { 175 + "last_updated": "2025-01-18", 176 + "sources": ["arxiv.org", "techcrunch.com", "nature.com"], 177 + "auto_fetch": false, 178 + "keywords": ["transformer", "attention", "llm", "research"] 179 + } 180 + ``` 181 + 182 + This allows for future automation of news gathering while maintaining manual curation quality. 183 + 184 + ## Activity Records 185 + 186 + The `activities/` directory within each facet stores both the configured activity types (`activities.jsonl`) and completed activity records organized by day (`{day}.jsonl`). Activity records represent completed spans of activity — periods where a specific activity type was continuously tracked across one or more recording segments. 187 + 188 + **File path pattern:** 189 + ``` 190 + facets/personal/activities/activities.jsonl # Configured activity types 191 + facets/personal/activities/20260209.jsonl # Completed records for the day 192 + facets/work/activities/20260209.jsonl 193 + facets/work/activities/20260209/coding_095809_303/session_review.md # Generated output 194 + ``` 195 + 196 + Each day file contains one JSON object per line, where each record represents a completed activity span: 197 + 198 + ```jsonl 199 + {"id": "coding_095809_303", "activity": "coding", "segments": ["095809_303", "100313_303", "100816_303", "101320_302"], "level_avg": 0.88, "description": "Developed extraction prompts using Claude Code and VS Code", "active_entities": ["Claude Code", "VS Code", "sunstone"], "created_at": 1770435619415} 200 + {"id": "meeting_090953_303", "activity": "meeting", "segments": ["090953_303", "091457_303", "092001_304", "092506_304", "093010_304"], "level_avg": 1.0, "description": "Sprint planning meeting with the engineering team", "active_entities": ["Alice", "Bob"], "created_at": 1770435619420} 201 + ``` 202 + 203 + ### Record ID scheme 204 + 205 + Activity record IDs follow the format `{activity_type}_{segment_key}` where `segment_key` is the segment in which the activity started. This is unique within a facet+day because only one activity of a given type can start in a given segment for one facet. 206 + 207 + ### Record fields 208 + 209 + - `id` (string) – Unique identifier: `{activity}_{start_segment_key}` (e.g., `coding_095809_303`) 210 + - `activity` (string) – Activity type ID from the facet's configured activities 211 + - `segments` (array of strings) – Ordered list of segment keys where this activity was active 212 + - `level_avg` (float) – Average engagement level across all segments (high=1.0, medium=0.5, low=0.25) 213 + - `description` (string) – AI-synthesized description of the full activity span 214 + - `active_entities` (array of strings) – Merged and deduplicated entity names from all segments 215 + - `created_at` (integer) – Unix timestamp in milliseconds when the record was created 216 + 217 + ### Lifecycle 218 + 219 + Activity records are created by the `activities` segment agent when it detects that an activity has ended: 220 + 221 + 1. The `activity_state` agent tracks per-segment, per-facet activity states with continuity via `since` fields. Each entry includes an `id` field (`{activity}_{since}`) that uniquely identifies the activity span, and `activity.live` events are emitted for active entries. 222 + 2. The `activities` agent runs after `activity_state` and compares previous vs. current segment states 223 + 3. When an activity ends (explicitly, implicitly, or via timeout), the agent walks the segment chain to collect all data 224 + 4. A record is written to the facet's day file with preliminary description 225 + 5. An LLM synthesizes all per-segment descriptions into a unified narrative 226 + 6. The record description is updated with the synthesized version 227 + 228 + **Segment flush:** If no new segments arrive for an extended period (1 hour), the supervisor triggers `sol dream --flush` on the last segment. Agents that declare `hook.flush: true` (like `activities`) run with `flush=True` in their context, treating all remaining active activities as ended. This ensures activities are recorded promptly even when the owner stops working, and prevents cross-day data loss. 229 + 230 + Records are written idempotently — duplicate IDs are skipped on re-runs. 231 + 232 + ### Generated output 233 + 234 + Activity-scheduled agents (`schedule: "activity"`) produce output that is stored alongside the activity records, organized by day and record ID: 235 + 236 + ``` 237 + facets/{facet}/activities/{day}/{activity_id}/{agent}.{ext} 238 + ``` 239 + 240 + For example, a `session_review` agent processing a coding activity would write to: 241 + ``` 242 + facets/work/activities/20260209/coding_095809_303/session_review.md 243 + ``` 244 + 245 + These output directories are only created when activity-scheduled agents run. The path is computed by `get_activity_output_path()` in `think/activities.py` and passed as `output_path` in the agent request. Output files are indexed for search via the `facets/*/activities/*/*/*.md` formatter pattern. 246 + 247 + ## Facet-Scoped Todos 248 + 249 + Todos are organized by facet in `facets/{facet}/todos/{day}.jsonl` where each file stores todo items as JSON Lines. Todos belong to a specific facet (e.g., "personal", "work", "research") and are completely separated by scope. 250 + 251 + **File path pattern:** 252 + ``` 253 + facets/personal/todos/20250110.jsonl 254 + facets/work/todos/20250110.jsonl 255 + facets/research/todos/20250112.jsonl 256 + ``` 257 + 258 + Each file contains one JSON object per line, with the line number (1-indexed) serving as the stable todo ID. 259 + 260 + ```jsonl 261 + {"text": "Draft standup update"} 262 + {"text": "Review PR #1234 for indexing tweaks", "time": "14:30"} 263 + {"text": "Morning planning session notes", "completed": true} 264 + {"text": "Cancel meeting with vendor", "cancelled": true} 265 + ``` 266 + 267 + ## Format Specification 268 + 269 + **JSONL structure:** 270 + 271 + Each line is a JSON object with the following fields: 272 + - `text` (required) – Task description 273 + - `time` (optional) – Scheduled time in `HH:MM` format (e.g., `"14:30"`) 274 + - `completed` (optional) – Set to `true` when task is done 275 + - `cancelled` (optional) – Set to `true` for soft-deleted tasks 276 + - `created_at` (optional) – Unix timestamp in milliseconds when todo was created 277 + - `updated_at` (optional) – Unix timestamp in milliseconds of last modification 278 + 279 + **Facet context:** 280 + - Facet is determined by the file location, not inline tags 281 + - Each facet has its own independent todo list for each day 282 + - Work todos (`facets/work/todos/`) are completely separate from personal todos (`facets/personal/todos/`) 283 + 284 + **Rules:** 285 + - Line number is the stable todo ID (1-indexed); todos are never removed, only cancelled 286 + - Append new todos at the end of the file to maintain stable line numbering 287 + - Mark completed items with `"completed": true` 288 + - Cancel items with `"cancelled": true` (soft delete preserves line numbers) 289 + 290 + **Tool Access:** 291 + All todo operations require both `day` and `facet` parameters: 292 + - `todo_list(day, facet)` – view numbered checklist for a specific facet 293 + - `todo_add(day, facet, text)` – append new todo 294 + - `todo_done(day, facet, line_number)` – mark complete 295 + - `todo_cancel(day, facet, line_number)` – cancel entry (soft delete) 296 + - `todo_upcoming(limit, facet=None)` – view upcoming todos (optionally filtered by facet) 297 + 298 + This facet-scoped structure provides true separation of concerns while enabling automated tools to manage tasks deterministically.
+144
talent/journal/references/logs.md
··· 1 + # Logs 2 + 3 + ## Action Logs 4 + 5 + Action logs record an audit trail of owner-initiated actions and agent tool calls. There are two types: 6 + 7 + - **Journal-level logs** (`config/actions/`) – actions not tied to a specific facet (settings changes, observer management) 8 + - **Facet-scoped logs** (`facets/{facet}/logs/`) – actions within a specific facet (todos, entities) 9 + 10 + ### Journal Action Logs 11 + 12 + The `config/actions/` directory records journal-level actions. Logs are organized by day as `config/actions/YYYYMMDD.jsonl`. 13 + 14 + ```json 15 + { 16 + "timestamp": "2025-12-16T07:33:05.135587+00:00", 17 + "source": "app", 18 + "actor": "settings", 19 + "action": "identity_update", 20 + "params": { 21 + "changed_fields": {"name": {"old": "John", "new": "John Doe"}} 22 + } 23 + } 24 + ``` 25 + 26 + ### Facet Action Logs 27 + 28 + The `logs/` directory within each facet records facet-scoped actions. Logs are organized by day as `facets/{facet}/logs/YYYYMMDD.jsonl`. 29 + 30 + ```json 31 + { 32 + "timestamp": "2025-12-16T07:33:05.135587+00:00", 33 + "source": "tool", 34 + "actor": "todos:todo", 35 + "action": "todo_add", 36 + "params": { 37 + "text": "Review project proposal" 38 + }, 39 + "facet": "work", 40 + "use_id": "1765870373972" 41 + } 42 + ``` 43 + 44 + ### Log Entry Fields 45 + 46 + Both log types share the same structure: 47 + 48 + - `timestamp` – ISO 8601 timestamp of the action 49 + - `source` – Origin type: "app" for web UI, "tool" for agent tools 50 + - `actor` – App or tool name that performed the action 51 + - `action` – Action name (e.g., "todo_add", "identity_update") 52 + - `params` – Action-specific parameters 53 + - `facet` – Facet name (only present in facet-scoped logs) 54 + - `use_id` – Agent ID (only present for agent tool actions) 55 + 56 + These logs enable auditing, debugging, and potential rollback of automated actions. 57 + 58 + ## Token Usage 59 + 60 + The `tokens/` directory tracks token usage from all AI model calls across the system. Usage data is organized by day as `tokens/YYYYMMDD.jsonl` where each file contains JSON Lines entries for that day's API calls. 61 + 62 + ### Token log format 63 + 64 + Each line in a token log file is a JSON object with the following structure: 65 + 66 + ```json 67 + { 68 + "timestamp": 1736812345000, 69 + "model": "gemini-2.5-flash", 70 + "context": "agent.default.20250113_143022", 71 + "segment": "143022_300", 72 + "usage": { 73 + "input_tokens": 1500, 74 + "output_tokens": 500, 75 + "total_tokens": 2000, 76 + "cached_tokens": 800, 77 + "reasoning_tokens": 200 78 + } 79 + } 80 + ``` 81 + 82 + Required fields: 83 + - `timestamp` – Unix timestamp in milliseconds (13 digits) 84 + - `model` – Model identifier (e.g., "gemini-2.5-flash", "gpt-5", "claude-sonnet-4-5") 85 + - `context` – Calling context (e.g., "agent.name.use_id" or "module.function:line") 86 + - `usage` – Token counts dictionary with normalized field names 87 + 88 + Optional fields: 89 + - `segment` – Recording segment key (e.g., "143022_300") when token usage is attributable to a specific observation window 90 + 91 + Usage fields (all optional depending on model capabilities): 92 + - `input_tokens` – Tokens in the prompt/input 93 + - `output_tokens` – Tokens in the response/output 94 + - `total_tokens` – Total tokens consumed 95 + - `cached_tokens` – Tokens served from cache (reduces cost) 96 + - `reasoning_tokens` – Tokens used for extended thinking/reasoning 97 + - `requests` – Number of API requests made (for batch operations) 98 + 99 + The logging system normalizes provider-specific formats (OpenAI, Gemini, Anthropic) into this unified schema for consistent cost tracking and analysis across all models. 100 + 101 + ## Agent Event Logs 102 + 103 + The `talents/` directory stores event logs for all AI talent sessions managed by Cortex. Each talent session produces a JSONL file containing the complete event history. 104 + 105 + **Directory layout:** 106 + - `<name>/` – per-agent subdirectory (e.g., `default/`, `entities--observer/`) 107 + - `<name>/<use_id>_active.jsonl` – currently running agent (renamed when complete) 108 + - `<name>/<use_id>.jsonl` – completed agent session 109 + - `<name>.log` – symlink to the latest completed run for each agent name 110 + - `<day>.jsonl` – day index with one summary line per agent that completed on that day 111 + 112 + The `use_id` is a Unix timestamp in milliseconds that uniquely identifies the session. 113 + 114 + **Event format (JSONL):** 115 + 116 + Each line is a JSON object with an `event` field indicating the event type: 117 + 118 + ```jsonl 119 + {"event": "start", "ts": 1755450767962, "name": "helper", "prompt": "Help me with...", "facet": "work"} 120 + {"event": "text", "ts": 1755450768000, "content": "I'll help you with that."} 121 + {"event": "tool_call", "ts": 1755450769000, "tool": "search", "params": {"query": "example"}} 122 + {"event": "tool_result", "ts": 1755450770000, "tool": "search", "result": "..."} 123 + {"event": "finish", "ts": 1755450771000, "result": "Here's what I found..."} 124 + ``` 125 + 126 + **Common event types:** 127 + - `start` – agent session started, includes name, prompt, and facet 128 + - `text` – streaming text output from the agent 129 + - `tool_call` – agent invoked a tool 130 + - `tool_result` – result returned from tool execution 131 + - `error` – error occurred during execution 132 + - `finish` – agent session completed, includes final result 133 + 134 + See [CORTEX.md](../../../docs/CORTEX.md) for agent architecture and spawning details. 135 + 136 + ## Service Health 137 + 138 + The `health/` directory contains log files for long-running services. 139 + 140 + **Files:** 141 + - `health/<service>.log` – log output for each service (e.g., `observe.log`, `cortex.log`, `convey.log`) 142 + - `health/retention.log` – JSONL log of retention purge operations with timestamps, files deleted, bytes freed, and per-segment details 143 + 144 + These logs are useful for debugging service issues. See [DOCTOR.md](../../../docs/DOCTOR.md) for diagnostics and troubleshooting guidance.
+47
talent/journal/references/storage.md
··· 1 + # Storage 2 + 3 + This document describes the layout of a **journal** directory where all captures, extracts, and insights are stored. Each dated `YYYYMMDD` folder is referred to as a **day**, and within each day captured content is organized into **segments** (timestamped duration folders). Each segment folder uses the format `HHMMSS_LEN/` where `HHMMSS` is the start time and `LEN` is the duration in seconds. This folder name serves as the **segment key**, uniquely identifying the segment within a given day. 4 + 5 + ## Top-Level Directory Structure 6 + 7 + | Directory/File | Purpose | 8 + |----------------|---------| 9 + | `chronicle/` | Container for daily capture folders (`YYYYMMDD/`) containing segments, extracts, and agent outputs | 10 + | `entities/` | Journal-level entity identity records (`<id>/entity.json`) | 11 + | `facets/` | Facet-specific data: entity relationships, todos, events, news, action logs | 12 + | `talents/` | Talent run logs in per-talent subdirectories (`<name>/<id>.jsonl`), day indexes (`<day>.jsonl`), and latest-run symlinks (`<name>.log`) | 13 + | `apps/` | App-specific storage (distinct from codebase `apps/`) | 14 + | `streams/` | Per-stream state files (`<name>.json`) tracking segment chains and sequence numbers | 15 + | `imports/` | Imported audio files and processing artifacts | 16 + | `tokens/` | Token usage logs from AI model calls, organized by day | 17 + | `indexer/` | Search index (`journal.sqlite` FTS5 database) | 18 + | `health/` | Service health logs (`<service>.log` files) | 19 + | `config/` | Configuration files and journal-level action logs | 20 + | `task_log.txt` | Optional log of utility runs in `[epoch]\tmessage` format | 21 + | `summary.md` | Journal-wide statistics summary (generated by `sol journal-stats`) | 22 + | `stats.json` | Detailed journal statistics in JSON format (generated by `sol journal-stats`) | 23 + 24 + ### Config directory 25 + 26 + - `config/journal.json` – owner configuration for the journal (optional, see [configuration](config.md)). 27 + - `config/convey.json` – Convey UI preferences (facet/app ordering, selected facet). 28 + - `config/actions/` – journal-level action logs (see [action logs](logs.md#action-logs)). 29 + 30 + ## App Storage 31 + 32 + The `apps/` directory provides storage space for Convey apps to persist configuration, data, and artifacts specific to this journal. Each app has its own directory at `apps/<app_name>/` where it can maintain app-specific state independent of the application codebase. 33 + 34 + Apps typically use `config.json` for journal-specific settings and create subdirectories for data storage (e.g., `cache/`, `data/`, `logs/`). This is distinct from the app metadata file (`apps/<app>/app.json` in the codebase) which defines icon, label, and facet support across all journals. See [APPS.md](../../../docs/APPS.md) for storage utilities (`get_app_storage_path`, `load_app_config`, `save_app_config`). 35 + 36 + ## Search Index 37 + 38 + The `indexer/` directory contains the full-text search index built from journal content. 39 + 40 + **Files:** 41 + - `indexer/journal.sqlite` – FTS5 SQLite database containing indexed chunks from agent outputs, events, entities, todos, and action logs 42 + 43 + The indexer converts content to markdown chunks via the formatters framework, then indexes with metadata fields (day, facet, agent) for filtering. Raw audio/screen transcripts are formattable but not indexed — agent outputs provide more useful search results. Use `get_journal_index()` from `think/indexer/journal.py` to access the database programmatically. 44 + 45 + Which content gets indexed is controlled by the `FORMATTERS` registry in `think/formatters.py`. Each entry maps a glob pattern to a formatter function and an `indexed` flag. The registry patterns must be specific enough to use as `Path.glob()` arguments from the journal root — adding a new content location requires a new entry. 46 + 47 + Run `sol indexer` to rebuild the index from current journal content.