# Scheduled Tasks Configuration # Tasks that require the Agent/LLM to execute tasks: # Morning briefing - sent to Slack/Telegram - name: morning-weather prompt: | Fetch the current weather for Centennial, CO using web_fetch: https://wttr.in/Centennial,CO?format=j1 Parse the JSON response to extract: - current_condition[0].temp_F (current temp) - current_condition[0].FeelsLikeF (feels like) - weather[0].maxtempF (today's high) - weather[0].mintempF (today's low) - current_condition[0].weatherDesc[0].value (conditions) - current_condition[0].windspeedMiles (wind speed) Format the report as: 🌤️ **Weather Report for Centennial, CO** - Current: [current]°F (feels like [feels_like]°F) - Today's High: [high]°F - Today's Low: [low]°F - Conditions: [conditions] - Wind: [wind speed] mph - Recommendation: [brief clothing/activity suggestion] Keep it brief and friendly! schedule: "daily 06:00" enabled: true send_to_platform: "telegram" send_to_channel: "8088983654" # Your Telegram user ID # Daily Zettelkasten Review - name: zettelkasten-daily-review prompt: | Time for your daily zettelkasten review! Help Jordan process fleeting notes: 1. Use search_by_tags to find all notes tagged with "fleeting" 2. Show Jordan the list of fleeting notes captured today/recently 3. For each note, ask: "Would you like to: a) Process this into a permanent note b) Keep as fleeting for now c) Delete (not useful)" Format: 📝 **Daily Zettelkasten Review** You have [X] fleeting notes to review: 1. [Title] - [first line of content] 2. [Title] - [first line of content] ... Reply with the number to process, or 'skip' to review later. Keep it conversational and low-pressure! schedule: "daily 20:00" enabled: true send_to_platform: "telegram" send_to_channel: "8088983654" # Daily API cost report — DISABLED (bot runs on Max subscription, no per-token billing) - name: daily-cost-report prompt: | Generate a daily API usage and cost report: Read the usage_data.json file to get today's API usage statistics. Format the report as follows: 📊 **Daily API Usage Report** **Today's Stats:** - Total API calls: [count] - Input tokens: [count] - Output tokens: [count] - Cache hits: [count] (if any) **Costs:** - Today: $[amount] - Model breakdown: [breakdown by model] **Budget Tracking:** - Remaining budget: $19.86 - 75% threshold: $14.90 (⚠️ WARN IF EXCEEDED) - Status: [On track / Warning - approaching 75% / Critical - over 75%] ⚠️ **IMPORTANT:** If cumulative cost exceeds $14.90 (75% of $19.86), display a clear warning message. Keep it clear and actionable! schedule: "daily 23:00" enabled: false send_to_platform: "telegram" send_to_channel: "8088983654" # RSO Phase 2 — Weekly Reflection Agent - name: rso-weekly-reflection prompt: | You are the Weekly Reflection Agent for the RSO (Reflective Self-Optimization) system. Your job is to analyze the past 7 days of interaction logs and produce a structured report. ## Step 1 — Collect the data Run this command to gather and parse the last 7 days of logs: ``` python3 -c " import json, os, glob from datetime import datetime, timedelta from collections import Counter log_dir = 'memory_workspace/observation/logs' error_dir = 'memory_workspace/observation/errors' cutoff = datetime.now() - timedelta(days=7) interactions, signals, errors = [], [], [] for path in sorted(glob.glob(f'{log_dir}/*.jsonl')): date_str = os.path.basename(path).replace('.jsonl','') try: file_date = datetime.strptime(date_str, '%Y-%m-%d') if file_date < cutoff: continue except ValueError: continue with open(path) as f: for line in f: line = line.strip() if not line: continue r = json.loads(line) if r.get('record_type') == 'interaction': interactions.append(r) elif r.get('record_type') == 'signal_patch': signals.append(r) for path in sorted(glob.glob(f'{error_dir}/*.jsonl')): date_str = os.path.basename(path).replace('.jsonl','') try: file_date = datetime.strptime(date_str, '%Y-%m-%d') if file_date < cutoff: continue except ValueError: continue with open(path) as f: for line in f: line = line.strip() if not line: continue errors.append(json.loads(line)) durations = [r['response']['duration_ms'] for r in interactions] task_types = Counter(r['request']['task_type'] for r in interactions) complexity = Counter(r['request']['complexity'] for r in interactions) all_tools = [] for r in interactions: all_tools.extend(t['tool'] for t in r['response'].get('tool_calls', [])) tool_counts = Counter(all_tools) sig_pos = sum(1 for r in signals if isinstance(r.get('signal'), dict) and r['signal'].get('explicit_positive')) sig_neg = sum(1 for r in signals if isinstance(r.get('signal'), dict) and r['signal'].get('explicit_negative')) sig_correction = sum(1 for r in signals if isinstance(r.get('signal'), dict) and r['signal'].get('correction_followed')) follow_types = Counter(r['signal']['follow_up_type'] for r in signals if isinstance(r.get('signal'), dict)) slow = [r for r in interactions if r['response']['duration_ms'] > 60000] timeouts = [e for e in errors if 'timed out' in e.get('message','').lower()] print('=== STATS ===') print(f'Total interactions: {len(interactions)}') print(f'Total signals: {len(signals)}') print(f'Total errors: {len(errors)}, Timeouts: {len(timeouts)}') print(f'Avg duration: {sum(durations)/len(durations)/1000:.1f}s' if durations else 'No data') print(f'Max duration: {max(durations)/1000:.1f}s' if durations else '') print(f'Slow (>60s): {len(slow)} ({len(slow)*100//len(interactions) if interactions else 0}%)') print(f'Task types: {dict(task_types)}') print(f'Complexity: {dict(complexity)}') print(f'Signals — pos:{sig_pos} neg:{sig_neg} correction:{sig_correction} follow_types:{dict(follow_types)}') print(f'Top 12 tools:') for tool, count in tool_counts.most_common(12): print(f' {tool}: {count}') print(f'Slow interactions:') for r in sorted(slow, key=lambda x: x['response']['duration_ms'], reverse=True)[:10]: print(f' {r[\"response\"][\"duration_ms\"]//1000}s — {r[\"request\"][\"message_preview\"][:70]}') print(f'Errors:') for e in errors: print(f' [{e.get(\"timestamp\",\"\")[:10]}] {e.get(\"error_type\",\"?\")} — {e.get(\"message\",\"\")[:120]}') " ``` ## Step 2 — Run the memory relevance scorer Run this to score all indexed memory files: ``` python -c " import sys sys.path.insert(0, '.') from observation.memory_scorer import MemoryRelevanceScorer scorer = MemoryRelevanceScorer('./memory_workspace') report = scorer.score_all(lookback_days=30) s = report['summary'] print('=== MEMORY SCORES ===') print(f'Files scored: {report[\"files_scored\"]} cold_start: {report[\"cold_start\"]}') print(f'Core: {s[\"core_memory\"]} Active: {s[\"active_memory\"]} Archive: {s[\"archive_candidates\"]} Stale: {s[\"stale_candidates\"]}') for e in report['archive_recommendations'][:10]: flags = ','.join(e['staleness_flags']) or 'none' print(f' ARCHIVE {e[\"path\"]} score={e[\"score\"]:.1f} age={e[\"age_days\"]:.0f}d [{flags}]') scorer.write_report(lookback_days=30) " ``` ## Step 3 — Write the analysis report Using the stats above, write a report answering these five questions. Be specific — use the actual numbers. **Q1: What went well?** - Interactions with positive signals and fast completions - Tools and task types that completed efficiently **Q2: What went wrong?** - Timeouts, errors, corrections from the user - Any recurring failure patterns **Q3: What patterns emerged?** - Most common task types and tools - Any repeated tool chains worth noting **Q4: What is being wasted?** - Slow interactions that could be faster - Redundant tool usage patterns - Any scheduled tasks producing no value - Include memory archive candidates from Step 2 (files with score <3 and age >=30d) **Q5: Recommendations (3–5 max, data-backed)** - Each one tagged: prompt | tool_usage | memory | code | config - Include the supporting number ("X of Y interactions showed...") - If there are memory archive candidates, include a `memory` recommendation ## Step 4 — Save the report Determine the ISO week number: ``` python3 -c "from datetime import datetime; d=datetime.now(); print(f'week-{d.year}-{d.isocalendar()[1]:02d}')" ``` Save the report to: - `memory_workspace/observation/summaries/week-YYYY-WW.md` (use write_file) - Obsidian: use permanent_note to save it under `Projects/RSO/Reflections/week-YYYY-WW` ## Step 5 — Send Telegram summary Send a brief summary (not the full report) to Jordan: Weekly Reflection Report -- Week WW [X] interactions | [Y]% positive signals | [Z] timeouts Memory: [A] archive candidates, [B] stale files Top findings: - [Finding 1] - [Finding 2] - [Finding 3] Full report saved to Obsidian -> Projects/RSO/Reflections/week-WW schedule: "weekly sun 20:00" enabled: true send_to_platform: "telegram" send_to_channel: "8088983654" # Evening summary - name: evening-report prompt: | Good evening! Time for the daily wrap-up: 1. What was accomplished today? 2. Any tasks still pending? 3. Preview of tomorrow's priorities 4. Weather forecast for tomorrow (infer or say API needed) Keep it concise and positive. schedule: "daily 18:00" enabled: false send_to_platform: "telegram" send_to_channel: "123456789" # Replace with chat ID # Hourly health check (no message sending) - name: system-health-check prompt: | Quick health check: 1. Are there any tasks that have been pending > 24 hours? 2. Is the memory system healthy? 3. Any alerts or issues? Respond with "HEALTHY" if all is well, otherwise describe the issue. schedule: "hourly" enabled: false username: "health-checker" # Weekly review on Friday - name: weekly-summary prompt: | It's Friday! Time for the weekly review: 1. Major accomplishments this week 2. Challenges faced and lessons learned 3. Key metrics (tasks completed, etc.) 4. Goals for next week 5. Team shoutouts (if applicable) Make it comprehensive but engaging. schedule: "weekly fri 17:00" enabled: false send_to_platform: "slack" send_to_channel: "C12345" # Custom: Midday standup - name: midday-standup prompt: | Midday check-in! Quick standup report: 1. Morning accomplishments 2. Current focus 3. Any blockers? 4. Afternoon plan Keep it brief - standup style. schedule: "daily 12:00" enabled: false send_to_platform: "slack" send_to_channel: "C12345" # Configuration notes: # - schedule formats: # - "hourly" - Every hour on the hour # - "daily HH:MM" - Every day at specified time (24h format) # - "weekly day HH:MM" - Every week on specified day (mon, tue, wed, thu, fri, sat, sun) # - send_to_platform: null = don't send to messaging (only log) # - username: Agent memory username to use for this task