Skip to content

Conversation

@ooloth
Copy link
Owner

@ooloth ooloth commented Nov 21, 2025

💪 What

Primary Changes: TIL Workflow System

  • /suggest-tils slash command - Interactive workflow for discovering and drafting TIL blog posts from git history
  • scan-git-for-tils skill - Python-based skill that scans GitHub commits for TIL-worthy topics, tracks assessed commits in Notion, and formats results for Claude evaluation
  • draft-til skill - Voice guide and workflow instructions for drafting TIL posts in the user's writing style
  • scan-notion-for-tils skill - Workflow for scanning Notion Writing database backlog for TIL opportunities
  • TIL workflow spec - Complete architecture and implementation documentation at .claude/specs/til-workflow.md

Secondary Changes: Infrastructure

  • CI workflow - GitHub Actions workflow testing Python skills (ruff linting, mypy type checking, pytest)
  • Skill template documentation - Expanded @template/README.md with Python best practices, PEP 723 patterns, and type safety guidelines
  • Bun tooling - Install/update/uninstall scripts for Bun runtime (used during TypeScript experimentation)
  • Global CLAUDE.md updates - Added TIL suggestion guidance and /suggest-tils command documentation

🤔 Why

  • Capture learning moments - Enables Claude to proactively suggest blog topics during problem-solving conversations and systematically scan git history for TIL-worthy commits
  • Maintain voice consistency - Provides detailed voice guide ensuring drafted TILs match the user's casual, direct writing style
  • Reduce context window usage - Implements git/Notion scanning as a Python skill (processing and filtering data in code) rather than via Claude tools, achieving 80-98% token reduction
  • Production-quality Python - Establishes patterns for type-safe, well-tested skills using modern Python tooling (uv, Pydantic v2, mypy, ruff)
  • Prevent duplicate work - Tracks assessed commits in Notion database to avoid re-evaluating the same commits across multiple scans

👀 Usage

Run the slash command to start the TIL workflow:

/suggest-tils

The workflow will:

  1. Prompt for date range (default: 30 days)
  2. Scan GitHub commits and filter out assessed commits
  3. Display markdown-formatted TIL candidates
  4. Let you select commits to draft
  5. Generate draft in your voice and publish to Notion with "Claude Draft" status
  6. Link draft back to commit tracking database

Individual skill usage (for debugging):

# Scan git history for TIL candidates
cd ~/.claude/skills/scan-git-for-tils
uv run scan_git.py 30  # last 30 days

# Run tests
uv run test_pure_functions.py

# Lint and type check
uv run --with ruff ruff check .
uv run --with mypy --with notion-client --with pydantic --with pytest mypy --python-version 3.11 .

👩‍🔬 How to validate

Test the complete workflow

  1. Ensure you have required tools:

    which gh op uv  # All should return paths
    gh auth status  # Verify GitHub authentication
    op account list # Verify 1Password authentication
  2. Run the slash command and test the full flow:

    /suggest-tils
    # Enter "7" for last 7 days
    # Select a commit number to draft
    # Review the generated draft
    # Check Notion Writing database for "Claude Draft" entry
    # Verify commit appears in TIL Assessed Commits database

Test the Python skill independently

  1. Navigate to skill directory:

    cd tools/claude/config/skills/scan-git-for-tils
  2. Run the scan script:

    uv run scan_git.py 30

    Expected: Markdown-formatted list of TIL candidates from last 30 days, excluding previously assessed commits

  3. Run tests:

    uv run test_pure_functions.py

    Expected: All tests pass (formatting, validation, mocking)

  4. Run linting and type checking:

    uv run --with ruff ruff check .
    uv run --with mypy --with notion-client --with pydantic --with pytest mypy --python-version 3.11 .

    Expected: No errors from either tool

Verify CI workflow

  1. Check that CI ran on this PR and passed all checks:

    • Ruff linting
    • Mypy type checking
    • Pytest tests
  2. The workflow runs automatically on:

    • Pull requests to main (when Python skill files change)
    • Pushes to main
    • Manual workflow dispatch

🔗 Related links

@ooloth ooloth marked this pull request as ready for review November 21, 2025 00:34
Copilot AI review requested due to automatic review settings November 21, 2025 00:34
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR introduces a /suggest-tils command that automates the discovery and drafting of TIL (Today I Learned) blog posts from git commit history. The system uses Claude to evaluate commits, ranks them by TIL potential, and creates drafts in Notion with automatic tracking.

Key Changes:

  • Python scripts fetch commits via GitHub API and manage Notion publishing workflow
  • Claude skills evaluate commit TIL potential and generate content matching user's writing voice
  • Automated linking between Writing database entries and commit tracker prevents duplicate suggestions

Reviewed Changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tools/claude/config/skills/scan-notion-for-tils/SKILL.md Documentation for planned Notion scanning feature (marked as under development)
tools/claude/config/skills/scan-git-for-tils/scan_git.py Fetches commits from GitHub, filters assessed ones from Notion, outputs JSON for Claude evaluation
tools/claude/config/skills/scan-git-for-tils/publish_til.py Creates Writing pages and tracker entries in Notion, handles markdown-to-blocks conversion
tools/claude/config/skills/scan-git-for-tils/SKILL.md Instructions for Claude on evaluating commits and ranking TIL suggestions
tools/claude/config/skills/draft-til/SKILL.md Comprehensive voice guide and formatting rules for generating TIL content
tools/claude/config/commands/suggest-tils.md Command orchestration workflow from scanning to publishing
tools/claude/config/CLAUDE.md Global hint for Claude to suggest TILs during problem-solving
.claude/specs/til-workflow.md Complete specification documenting architecture and implementation approach

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@claude
Copy link

claude bot commented Nov 21, 2025

PR Review: TIL Workflow Implementation

This is an impressive, well-thought-out implementation of an automated TIL content generation workflow! The architecture is solid and the code quality is generally high. Below are my findings organized by category.

✅ Strengths

Architecture & Design

  • Excellent separation of concerns: Skills are modular and single-purpose (scan vs. draft vs. publish)
  • Smart data flow: Using JSON between scripts for composability
  • Thoughtful UX: Interactive prompts, ranked suggestions, and user approval before publishing
  • Database-backed deduplication: Notion tracker prevents duplicate suggestions across machines
  • Parallel processing: ThreadPoolExecutor for GitHub API calls (scan_git.py:158)

Code Quality

  • Clean Python: Good use of type hints, docstrings, and functional decomposition
  • Comprehensive voice guide: Detailed writing style documentation with excellent examples
  • Robust error handling: Graceful fallbacks (scan_git.py:129-130)
  • Secure secret management: 1Password CLI integration instead of hardcoded credentials

Documentation

  • Outstanding spec document: .claude/specs/til-workflow.md is thorough and professional
  • Clear usage examples: Each skill has usage documentation
  • Safety rules: Well-defined guardrails for Claude's behavior

🔍 Issues & Recommendations

🔴 High Priority

1. Rate Limiting Risk (scan_git.py:158)

with ThreadPoolExecutor(max_workers=15) as executor:

Issue: 15 concurrent GitHub API requests could hit rate limits (5,000/hour authenticated)
Risk: For users with many commits, this could fail or get throttled
Recommendation:

  • Reduce to 5-10 workers
  • Add rate limit error handling
  • Consider using gh api --paginate with built-in throttling

2. Error Handling Silences Failures (scan_git.py:165-168)

try:
    commit["files"] = future.result()
except Exception:
    commit["files"] = []

Issue: Broad exception handling hides legitimate errors (network, auth, API changes)
Recommendation:

except Exception as e:
    # Log warning for debugging but continue
    print(f"Warning: Failed to fetch files for {commit['hash']}: {e}", file=sys.stderr)
    commit["files"] = []

3. Missing Input Validation (publish_til.py:287)

Issue: After JSON validation, there's no sanitization of markdown content or title length
Risk: Notion API has limits:

  • Title max: 2000 characters (enforced for Message at line 182)
  • Rich text max: 2000 characters per block
    Recommendation: Add validation:
if len(input_data["title"]) > 2000:
    print(json.dumps({"error": "Title exceeds 2000 characters"}))
    sys.exit(1)

4. Page ID Extraction Fragile (publish_til.py:268-281)

parts = url.rstrip("/").split("-")
candidate = parts[-1].split("/")[-1]

Issue: Assumes Notion URL format. If Notion changes URL structure, this breaks silently
Test case that fails: URLs with hyphens in title
Recommendation: Use regex or parse last 32-character UUID segment

🟡 Medium Priority

5. Incomplete Markdown Parsing (publish_til.py:194-265)

Missing support:

  • Inline formatting (bold **text**, italic *text*, code `text`)
  • Links [text](url)
  • Block quotes >
  • Emojis in markdown (might render incorrectly)

Impact: TILs won't match the voice guide's examples that use inline formatting
Recommendation: Either document limitations or use a proper markdown parser like markdown-it-py

6. Date Parsing Assumes ISO Format (scan_git.py:254-255)

dt = datetime.fromisoformat(iso_date.replace("Z", "+00:00"))

Issue: GitHub sometimes returns dates in RFC3339 format with milliseconds
Edge case: 2025-01-15T12:34:56.789Z will parse, but assumptions should be documented
Recommendation: Add format documentation or use dateutil.parser

7. No Retry Logic for API Calls

Issue: Network hiccups or transient Notion/GitHub API errors cause immediate failure
Impact: User has to restart entire workflow
Recommendation: Add exponential backoff for API requests, especially in notion_request()

8. Hardcoded Database IDs

NOTION_ASSESSED_COMMITS_DB = "928fcd9e47a84f98824790ac5a6d37ca"
WRITING_DATA_SOURCE_ID = "c296db5b-d2f1-44d4-abc6-f9a05736b143"

Issue: Not configurable for other users (though this is personal dotfiles)
Recommendation: Consider environment variables or config file for reusability

🟢 Low Priority

9. Code Style Consistency

  • Some functions return empty string "" on error, others return empty list []
  • Mix of urllib.request (manual) and subprocess (for gh CLI) - both work but inconsistent approach
  • Consider using requests library for more readable HTTP code

10. Performance Optimization

  • get_assessed_commits_from_notion() loads all commits into memory (scan_git.py:46)
  • For large databases (1000+ assessed commits), this could be slow
  • Consider caching or lazy loading

11. Test Coverage

  • No unit tests for critical functions like markdown_to_blocks(), extract_page_id(), should_skip_commit()
  • Consider adding tests for Python scripts (even if CI only runs shellcheck)

🔒 Security Review

✅ Good Practices

  • Secrets via 1Password CLI (not hardcoded)
  • No user input directly interpolated into shell commands
  • JSON parsing before use

⚠️ Minor Concerns

  1. Command injection risk is minimal but subprocess.run() uses list format (good)
  2. No HTTPS verification disabled - urllib uses system certs (good)
  3. Markdown content not sanitized before Notion API - assumes trusted input (acceptable for personal use)

📋 Testing Suggestions

  1. Edge cases to test:

    • Run with 0 commits found
    • Run with all commits already assessed
    • Run with very long commit message (2000+ chars)
    • Run with network disconnected (graceful failure?)
    • Run with expired GitHub/Notion token
  2. Integration test:

    • Full /suggest-tils workflow end-to-end
    • Verify tracker entry creation and linking
    • Verify duplicate detection works
  3. Load test:

    • Scan 365 days with 500+ commits
    • Verify rate limiting doesn't fail

💭 Suggestions for Future Enhancement

  1. Add dry-run mode: Preview what would be created without API calls
  2. Improve markdown parser: Support inline formatting, links, tables
  3. Add undo/archive command: Remove false positive TIL drafts
  4. Export functionality: Generate markdown files locally before publishing
  5. Analytics: Track which repos/commit types generate best TILs
  6. Batch processing: Draft multiple TILs at once

🎯 Final Verdict

Approve with suggestions

This is production-quality code for a personal dotfiles repo. The architecture is sound, the implementation is clean, and the documentation is exceptional. The identified issues are mostly edge cases and improvements rather than blockers.

Recommended Before Merge:

  1. Fix rate limiting (reduce ThreadPoolExecutor workers)
  2. Improve error messages (don't silently catch all exceptions)
  3. Add title length validation

Consider Post-Merge:

  • Enhance markdown parser
  • Add retry logic for API calls
  • Write tests for critical functions

Great work on this feature! The voice guide is particularly impressive - it captures a distinct writing style with specific, actionable examples. 🎉

@ooloth ooloth changed the title Claude Code: scan recent git commits + suggest lessons learned + draft write-ups Add TIL workflow system for Claude Nov 22, 2025
@ooloth ooloth merged commit 5f8ccae into main Nov 22, 2025
2 checks passed
@ooloth ooloth deleted the have-claude-suggest-and-draft-til-style-blog-posts branch November 22, 2025 06:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants