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
|
||||
|
||||
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."
|
||||
|
|
|
|||
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