build: garden update 2026-04-18 08:39 — content/sessions/2026-04-18-session.md scripts/garden-session.sh scripts/parse_daily.py
This commit is contained in:
parent
51e4fac4db
commit
5dec7c1436
3 changed files with 126 additions and 31 deletions
32
content/sessions/2026-04-18-session.md
Normal file
32
content/sessions/2026-04-18-session.md
Normal file
|
|
@ -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 %}}
|
||||||
|
|
@ -5,38 +5,59 @@
|
||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
|
||||||
DATE=${1:-$(date +%Y-%m-%d)}
|
DATE=${1:-$(date +%Y-%m-%d)}
|
||||||
DAILY_PATH="~/.napkin/daily/${DATE}.md"
|
DAILY_FILE_PATH="$HOME/.napkin/daily/${DATE}.md"
|
||||||
DRAFT_PATH="content/sessions/${DATE}-session.md"
|
DRAFT_PATH="content/sessions/${DATE}-session.md"
|
||||||
|
|
||||||
echo "Generating session draft for ${DATE}..."
|
echo "Generating session draft for ${DATE}..."
|
||||||
|
|
||||||
# Read daily note
|
# Check if daily note exists
|
||||||
napkin daily read --file "${DATE}" > /tmp/daily-${DATE}.md || {
|
if [ ! -f "$DAILY_FILE_PATH" ]; then
|
||||||
echo "No daily note for ${DATE}"
|
echo "No daily note for ${DATE} at ${DAILY_FILE_PATH}"
|
||||||
exit 1
|
exit 1
|
||||||
}
|
fi
|
||||||
|
|
||||||
# Extract YAML frontmatter (simple sed, assumes standard format)
|
# Use the python parser to get structured data
|
||||||
FRONTMATTER=$(sed -n '/^---/,$p' /tmp/daily-${DATE}.md | sed '/^---/q' | tail -n +2)
|
JSON_DATA=$("$SCRIPT_DIR/parse_daily.py" "$DAILY_FILE_PATH")
|
||||||
SUMMARY=$(echo "${FRONTMATTER}" | grep '^summary:' | sed 's/^summary: //')
|
|
||||||
KEYWORDS=$(echo "${FRONTMATTER}" | grep '^keywords:' | sed 's/^keywords: \\[\\(.*\\)\\]/\\1/' | tr -d '[], "')
|
if [[ -z "$JSON_DATA" || "$JSON_DATA" == "{}" ]]; then
|
||||||
WORK=$(sed -n '/^**Work:**/,/^$/p' /tmp/daily-${DATE}.md | tail -n +2)
|
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)
|
# Determine fragment types from keywords (simple mapping)
|
||||||
FRAGMENTS=()
|
FRAGMENTS=()
|
||||||
if [[ "${KEYWORDS}" == *operational* || ${KEYWORDS} == *fix* ]]; then
|
RAW_KEYWORDS=$(echo "$JSON_DATA" | jq -r '.keywords[]? // ""')
|
||||||
FRAGMENTS+=("fix")
|
|
||||||
fi
|
for keyword in $RAW_KEYWORDS; do
|
||||||
if [[ "${KEYWORDS}" == *build* || ${KEYWORDS} == *protocol* ]]; then
|
case "$keyword" in
|
||||||
FRAGMENTS+=("build")
|
operational|fix|debug)
|
||||||
fi
|
FRAGMENTS+=("fix")
|
||||||
# Add more mappings...
|
;;
|
||||||
|
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
|
# 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
|
date: ${DATE}T00:00:00Z
|
||||||
tags: [session, ${KEYWORDS}]
|
tags: [session, ${KEYWORDS}]
|
||||||
draft: true
|
draft: true
|
||||||
|
|
@ -45,12 +66,12 @@ draft: true
|
||||||
# Session ${DATE}
|
# Session ${DATE}
|
||||||
|
|
||||||
## Summary
|
## Summary
|
||||||
{{% fragment type="summary" %}}
|
{{% fragment type="summary" %}}
|
||||||
${SUMMARY}
|
${SUMMARY}
|
||||||
{{% /fragment %}}
|
{{% /fragment %}}
|
||||||
|
|
||||||
## Work Highlights
|
## Work Highlights
|
||||||
{{% fragment type="work" %}}
|
{{% fragment type="work" %}}
|
||||||
${WORK}
|
${WORK}
|
||||||
{{% /fragment %}}
|
{{% /fragment %}}
|
||||||
|
|
||||||
|
|
@ -58,14 +79,12 @@ ${WORK}
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# Add dynamic fragments
|
# Add dynamic fragments
|
||||||
for type in "${FRAGMENTS[@]}"; do
|
for type in "${FRAGMENTS[@]}"; do
|
||||||
echo "
|
echo "
|
||||||
{{% fragment type=\"${type}\" %}}
|
{{% fragment type=\"${type}\" %}}
|
||||||
[Details for ${type}]
|
[Details for ${type}]
|
||||||
{{% /fragment %}}" >> "${DRAFT_PATH}"
|
{{% /fragment %}}" >> "${DRAFT_PATH}"
|
||||||
done
|
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."
|
|
||||||
|
|
|
||||||
44
scripts/parse_daily.py
Executable file
44
scripts/parse_daily.py
Executable file
|
|
@ -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])
|
||||||
Loading…
Add table
Add a link
Reference in a new issue