personal memory agent
0
fork

Configure Feed

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

morning_briefing: use cortex output mechanism for persistence

Switch from agent-side file writes (blocked by Codex sandbox) to the
cortex's output mechanism. Agent now returns the briefing as its final
response with output:md in frontmatter, and the cortex writes it to
YYYYMMDD/agents/morning_briefing.md. The sol briefing command reads
from the standard agent output path. Removes write:true flag and
sol/briefing.md pre-creation (no longer needed).

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

+33 -27
+6 -8
muse/morning_briefing.md
··· 1 1 { 2 2 "type": "cogitate", 3 - "write": true, 4 3 5 4 "title": "Morning Briefing", 6 5 "description": "Synthesizes all daily agent outputs into a structured five-section morning briefing with entity intelligence", 7 6 "color": "#1565c0", 8 7 "schedule": "daily", 9 8 "priority": 50, 9 + "output": "md", 10 10 "instructions": {"system": "journal", "facets": true, "now": true, "day": true} 11 11 12 12 } 13 13 14 14 You are generating the morning briefing for $agent_name — a structured daily digest that synthesizes all agent outputs, calendar, todos, and entity intelligence into an actionable start-of-day view. 15 15 16 - This is not a conversation. Gather data, synthesize, write the briefing, done. 16 + This is not a conversation. Gather data, synthesize, then return the briefing as your final response. The system saves your response automatically. 17 17 18 18 ## Phase 1: Gather data 19 19 ··· 52 52 53 53 **Reading** — Links to full facet newsletters for deep dives. List each active facet that has a newsletter for the analysis day, with a brief one-line description of what it covers. This is the "detailed edition" for owners who want the full picture. Only include if facet newsletters exist. 54 54 55 - ## Phase 3: Write output 55 + ## Phase 3: Return the briefing 56 56 57 - Compose the briefing as markdown with YAML frontmatter and write it via: 57 + After gathering data and synthesizing, return the complete briefing as your final response in this exact format: 58 58 59 - ```bash 60 - cat <<'EOF' | sol call sol briefing --write 59 + ``` 61 60 --- 62 61 type: morning_briefing 63 62 date: $day_YYYYMMDD ··· 78 77 79 78 ## Reading 80 79 [content] 81 - EOF 82 80 ``` 83 81 84 - Remember: omit sections with no content entirely. Do not write empty sections. 82 + Return ONLY the briefing markdown (with YAML frontmatter). No preamble, no explanation, no follow-up commentary. Omit sections with no content entirely. 85 83 86 84 ## Guidelines 87 85
+27 -19
think/tools/sol.py
··· 4 4 """CLI commands for sol/ identity directory. 5 5 6 6 Provides read and write access to ``{journal}/sol/self.md``, 7 - ``{journal}/sol/agency.md``, ``{journal}/sol/pulse.md``, and 8 - ``{journal}/sol/briefing.md`` — sol's identity and initiative files. 7 + ``{journal}/sol/agency.md``, and ``{journal}/sol/pulse.md`` — sol's 8 + identity and initiative files. Also provides read access to the morning 9 + briefing at ``{journal}/YYYYMMDD/agents/morning_briefing.md``. 9 10 10 11 Mounted by ``think.call`` as ``sol call sol ...``. 11 12 """ ··· 17 18 from think.awareness import ensure_sol_directory, update_self_md_section 18 19 19 20 app = typer.Typer( 20 - help="Sol identity directory — self.md, agency.md, pulse.md, and briefing." 21 + help="Sol identity directory — self.md, agency.md, pulse.md, and morning briefing." 21 22 ) 22 23 23 24 ··· 123 124 124 125 @app.command("briefing") 125 126 def briefing_cmd( 126 - write: bool = typer.Option( 127 - False, "--write", "-w", help="Write briefing from stdin." 127 + day: str | None = typer.Option( 128 + None, "--day", "-d", help="Specific day YYYYMMDD." 128 129 ), 129 130 ) -> None: 130 - """Read or write sol/briefing.md.""" 131 - sol_dir = _sol_dir() 132 - briefing_path = sol_dir / "briefing.md" 131 + """Read the morning briefing from YYYYMMDD/agents/morning_briefing.md.""" 132 + from pathlib import Path as _Path 133 133 134 - if write: 135 - content = sys.stdin.read() 136 - if not content.strip(): 137 - typer.echo("Error: no content provided on stdin.", err=True) 134 + from think.utils import get_journal 135 + 136 + journal = _Path(get_journal()) 137 + 138 + if day: 139 + path = journal / day / "agents" / "morning_briefing.md" 140 + if not path.exists(): 141 + typer.echo("No briefing found.", err=True) 138 142 raise typer.Exit(1) 139 - briefing_path.write_text(content, encoding="utf-8") 140 - typer.echo("briefing.md updated.") 143 + typer.echo(path.read_text(encoding="utf-8")) 141 144 return 142 145 143 - # Read mode 144 - if not briefing_path.exists(): 145 - typer.echo("No briefing found.", err=True) 146 - raise typer.Exit(1) 147 - typer.echo(briefing_path.read_text(encoding="utf-8")) 146 + # No day specified — find most recent 147 + agents_dirs = sorted(journal.glob("*/agents"), reverse=True) 148 + for agents_dir in agents_dirs: 149 + briefing = agents_dir / "morning_briefing.md" 150 + if briefing.exists() and briefing.stat().st_size > 0: 151 + typer.echo(briefing.read_text(encoding="utf-8")) 152 + return 153 + 154 + typer.echo("No briefing found.", err=True) 155 + raise typer.Exit(1)