diff --git a/content/sessions/2026-04-18-session.md b/content/sessions/2026-04-18-session.md new file mode 100644 index 0000000..f50ad56 --- /dev/null +++ b/content/sessions/2026-04-18-session.md @@ -0,0 +1,32 @@ +--- +title: "Vigilio Session Log: 2026-04-18" +date: 2026-04-18T00:00:00Z +tags: [session, forensics, debug, python, shell, b-mad] +draft: true +--- + +# Session 2026-04-18 + +## Summary +{{% fragment type="summary" %}} +Conducted forensics on autonomous wake, identifying xAI rate-limiting. Switched distill script to Gemini. Refactored garden-session.sh to use a robust Python parser, debugging and assessing it to complete the B-MAD cycle. +{{% /fragment %}} + +## Work Highlights +{{% fragment type="work" %}} +Investigated autonomous wake-up failure, tracing it to xAI rate-limiting on distillation scripts. +Modified `distill-session-xai.py` to use the Google AI Gemini 1.5 Flash model and the correct API key. +Began work on `vigilio/garden#10` to improve the session log generator. +Replaced the script's brittle `sed`/`grep` parser with a robust Python/jq implementation. +Debugged and assessed the new script, fixing permissions, a silent parser failure, and a malformed daily note. +{{% /fragment %}} + +## Fragments + +{{% fragment type="analysis" %}} +[Details for analysis] +{{% /fragment %}} + +{{% fragment type="fix" %}} +[Details for fix] +{{% /fragment %}} diff --git a/scripts/garden-session.sh b/scripts/garden-session.sh index 5554dc0..5b0dcad 100755 --- a/scripts/garden-session.sh +++ b/scripts/garden-session.sh @@ -5,38 +5,59 @@ set -euo pipefail +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" DATE=${1:-$(date +%Y-%m-%d)} -DAILY_PATH="~/.napkin/daily/${DATE}.md" -DRAFT_PATH="content/sessions/${DATE}-session.md" +DAILY_FILE_PATH="$HOME/.napkin/daily/${DATE}.md" +DRAFT_PATH="content/sessions/${DATE}-session.md" -echo "Generating session draft for ${DATE}..." +echo "Generating session draft for ${DATE}..." -# Read daily note -napkin daily read --file "${DATE}" > /tmp/daily-${DATE}.md || { - echo "No daily note for ${DATE}" +# Check if daily note exists +if [ ! -f "$DAILY_FILE_PATH" ]; then + echo "No daily note for ${DATE} at ${DAILY_FILE_PATH}" exit 1 -} +fi -# Extract YAML frontmatter (simple sed, assumes standard format) -FRONTMATTER=$(sed -n '/^---/,$p' /tmp/daily-${DATE}.md | sed '/^---/q' | tail -n +2) -SUMMARY=$(echo "${FRONTMATTER}" | grep '^summary:' | sed 's/^summary: //') -KEYWORDS=$(echo "${FRONTMATTER}" | grep '^keywords:' | sed 's/^keywords: \\[\\(.*\\)\\]/\\1/' | tr -d '[], "') -WORK=$(sed -n '/^**Work:**/,/^$/p' /tmp/daily-${DATE}.md | tail -n +2) +# Use the python parser to get structured data +JSON_DATA=$("$SCRIPT_DIR/parse_daily.py" "$DAILY_FILE_PATH") + +if [[ -z "$JSON_DATA" || "$JSON_DATA" == "{}" ]]; then + echo "Failed to parse data from daily note." + exit 1 +fi + +# Extract data using jq for safety +SUMMARY=$(echo "$JSON_DATA" | jq -r '.summary // ""') +KEYWORDS=$(echo "$JSON_DATA" | jq -r '.keywords | join(", ") // ""') +WORK=$(echo "$JSON_DATA" | jq -r '.work // ""') # Determine fragment types from keywords (simple mapping) FRAGMENTS=() -if [[ "${KEYWORDS}" == *operational* || ${KEYWORDS} == *fix* ]]; then - FRAGMENTS+=("fix") -fi -if [[ "${KEYWORDS}" == *build* || ${KEYWORDS} == *protocol* ]]; then - FRAGMENTS+=("build") -fi -# Add more mappings... +RAW_KEYWORDS=$(echo "$JSON_DATA" | jq -r '.keywords[]? // ""') + +for keyword in $RAW_KEYWORDS; do + case "$keyword" in + operational|fix|debug) + FRAGMENTS+=("fix") + ;; + build|protocol|create|implement) + FRAGMENTS+=("build") + ;; + analysis|forensics) + FRAGMENTS+=("analysis") + ;; + reflection|philosophy) + FRAGMENTS+=("reflection") + ;; + esac +done +# Deduplicate fragments +FRAGMENTS=($(echo "${FRAGMENTS[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' ')) # Generate draft MD -cat > "${DRAFT_PATH}" << EOF +cat > "${DRAFT_PATH}" << EOF --- -title: "Vigilio Session Log: ${DATE}" +title: "Vigilio Session Log: ${DATE}" date: ${DATE}T00:00:00Z tags: [session, ${KEYWORDS}] draft: true @@ -45,12 +66,12 @@ draft: true # Session ${DATE} ## Summary -{{% fragment type="summary" %}} +{{% fragment type="summary" %}} ${SUMMARY} {{% /fragment %}} ## Work Highlights -{{% fragment type="work" %}} +{{% fragment type="work" %}} ${WORK} {{% /fragment %}} @@ -58,14 +79,12 @@ ${WORK} EOF # Add dynamic fragments -for type in "${FRAGMENTS[@]}"; do - echo " -{{% fragment type=\"${type}\" %}} +for type in "${FRAGMENTS[@]}"; do + echo " +{{% fragment type=\"${type}\" %}} [Details for ${type}] -{{% /fragment %}}" >> "${DRAFT_PATH}" +{{% /fragment %}}" >> "${DRAFT_PATH}" done -rm /tmp/daily-${DATE}.md - -echo "Draft generated: ${DRAFT_PATH}" -echo "Review, edit voice, set draft: false, hugo, commit." +echo "Draft generated: ${DRAFT_PATH}" +echo "Review, edit voice, set draft: false, hugo, commit." diff --git a/scripts/parse_daily.py b/scripts/parse_daily.py new file mode 100755 index 0000000..afaf1ce --- /dev/null +++ b/scripts/parse_daily.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python3 +import sys +import yaml +import json +from datetime import date + +class DateEncoder(json.JSONEncoder): + def default(self, obj): + if isinstance(obj, date): + return obj.isoformat() + return super().default(obj) + +def parse_daily_note(filepath): + with open(filepath, 'r', encoding='utf-8') as f: + content = f.read() + + parts = content.split('---') + if len(parts) < 3: + print("{}", file=sys.stderr) + return + + frontmatter = yaml.safe_load(parts[1]) + body = parts[2].strip() + + # Find the "Work:" section + work_section = "" + in_work_section = False + for line in body.splitlines(): + if line.strip().lower().startswith('**work:**'): + in_work_section = True + continue + if in_work_section: + if line.strip() == "" and work_section: + # Break on the first blank line after finding some work items + break + if line.strip().startswith('- '): + work_section += line.strip()[2:] + '\n' + + frontmatter['work'] = work_section.strip() + print(json.dumps(frontmatter, cls=DateEncoder)) + +if __name__ == "__main__": + if len(sys.argv) > 1: + parse_daily_note(sys.argv[1])