Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
9c0b417
claude: commit til workflow spec
ooloth Nov 20, 2025
21d82ad
claude: add draft-til skill with content, voice and notion workflow i…
ooloth Nov 20, 2025
f78760b
claude: add scan-git-for-tils skill
ooloth Nov 20, 2025
45c97f1
claude(scan-git-for-tils): use gh to search all recent commits, not j…
ooloth Nov 20, 2025
63af650
claude(scan-git-for-tils): track previously assessed commits in a not…
ooloth Nov 20, 2025
7a4895d
claude: add scan-notion-for-tils skill
ooloth Nov 20, 2025
b9622af
claude: add suggest-tils slash command
ooloth Nov 20, 2025
881b1a5
claude: encourage to notice TIL topic opportunities on the fly
ooloth Nov 20, 2025
6058882
claude(scan-git-for-tils): make concurrent requests to save time
ooloth Nov 20, 2025
3658de3
claude(scan-git-for-tils): leave it to the llm to find the valuable c…
ooloth Nov 20, 2025
27c6ead
claude(scan-git-for-tils): track commit date for my reference
ooloth Nov 20, 2025
9f204b5
claude(draft-til): clarify spirit of the style guide to get closer to…
ooloth Nov 20, 2025
317de8a
claude(suggest-tils): make git backlog timeframe an option
ooloth Nov 20, 2025
6daa2ff
claude(scan-git-for-tils): only mark discussed commits as "assessed" …
ooloth Nov 20, 2025
4615423
claude(draft-til): link draft to commit tracking db
ooloth Nov 20, 2025
57fdfb5
claude(scan-git-for-tils): let python handle all data fetching
ooloth Nov 20, 2025
1141332
claude(scan-git-for-tils): let python handle all the notion updating …
ooloth Nov 20, 2025
87629c1
claude(scan-git-for-tils): track commits with previously drafted posts
ooloth Nov 21, 2025
6ec2628
claude(scan-git-for-tils): rank recommended tils best to worst
ooloth Nov 21, 2025
3ece76b
Merge branch 'main' into have-claude-suggest-and-draft-til-style-blog…
ooloth Nov 21, 2025
9b6d3ca
fix: address pr review comments
ooloth Nov 21, 2025
12c77f2
claude(scan-git-for-tils): test pure functions used
ooloth Nov 21, 2025
444de30
claude(scan-git-for-tils): use the notion-client python sdk
ooloth Nov 21, 2025
631307a
ci: add test workflow for Python-based Claude skills
ooloth Nov 21, 2025
c029841
ci: rename workflow to 'Test Claude / Skills'
ooloth Nov 21, 2025
a22fc3d
claude(scan-git-for-tils): test the initial fetch from the commits db
ooloth Nov 21, 2025
49b8a58
refactor: migrate scan_git.py to Notion SDK
ooloth Nov 21, 2025
ce59aab
claude(scan-git-for-tils): break files up into packages and smaller m…
ooloth Nov 21, 2025
1fb270f
claude(scan-git-for-tils): fix op mocking so it's bypassed
ooloth Nov 21, 2025
083cdbb
claude(scan-git-for-tils): extract helper functions to make long func…
ooloth Nov 21, 2025
8bb5061
claude(scan-git-for-tils): use pydantic for inputs and dataclasses fo…
ooloth Nov 21, 2025
a6aef9a
claude: prefer future annotations in python
ooloth Nov 21, 2025
0e9fc3e
claude(scan-git-for-tils): fix tests
ooloth Nov 21, 2025
6c413a4
claude(scan-git-for-tils): scaffold smaller modules
ooloth Nov 21, 2025
168147c
claude(scan-git-for-tils): break up a couple modules
ooloth Nov 21, 2025
d5112dd
claude(scan-git-for-tils): add ruff and mypy
ooloth Nov 21, 2025
a3ce31e
claude(scan-git-for-tils): test markdown formatting
ooloth Nov 21, 2025
8283c4d
claude(scan-git-for-tils): fix ci failures with uv --with ...
ooloth Nov 21, 2025
d1b9e58
claude(scan-git-for-tils): separate ruff vs mypy vs test runs in ci
ooloth Nov 21, 2025
61d35bd
claude(scan-git-for-tils): make mypy less strict for now
ooloth Nov 21, 2025
8eb55d1
claude(scanning-git-for-tils): port to ts for comparison
ooloth Nov 21, 2025
0e9d384
claude(scanning-git-for-tils): fix lint and type errors
ooloth Nov 21, 2025
10d62bd
ci: run ts skills checks and tests as well
ooloth Nov 21, 2025
baa49f4
bun: add install, update, uninstall scripts
ooloth Nov 22, 2025
2f13d37
claude(scanning-git-for-tils): convert ts version from deno to bun
ooloth Nov 22, 2025
14b786f
claude(scanning-git-for-tils): update the notion sdk to latest
ooloth Nov 22, 2025
8e31cbd
claude(scanning-git-for-tils): add GET to fix gh api call
ooloth Nov 22, 2025
9eb6170
op: update constant name
ooloth Nov 22, 2025
4a6fd70
claude(skills): use latest notion api version
ooloth Nov 22, 2025
02d4b43
ruff: remove unused import
ooloth Nov 22, 2025
2c4548d
mypy: ignore third party code
ooloth Nov 22, 2025
46145d5
claude(skills): delete ts copy of git tils skill
ooloth Nov 22, 2025
df40bdb
claude(skills): fix test mocks
ooloth Nov 22, 2025
53bede1
claude(skills): fix circular import
ooloth Nov 22, 2025
58de240
claude(skills): raise error if retrieving 1p secret fails
ooloth Nov 22, 2025
e5bb9fe
ruff: remove unused import
ooloth Nov 22, 2025
c35b92d
claude(skills): scaffold test folders
ooloth Nov 22, 2025
a5ae7ee
claude(skills): use pydantic v2 syntax
ooloth Nov 22, 2025
b18ba0f
claude(skills): remove unnecessary missing imports mypy rule
ooloth Nov 22, 2025
dd3bf90
claude(skills): remove unnecessary unused configs rule
ooloth Nov 22, 2025
cb1c24a
claude(skills): remove redundant ruff rules
ooloth Nov 22, 2025
17fede0
claude(skills): add readme to skill
ooloth Nov 22, 2025
73ccc5e
claude(skills): clarify what git scan does
ooloth Nov 22, 2025
0b5429f
claude(skills): update template docs to reflect python patterns
ooloth Nov 22, 2025
4669b05
claude(skills): add function signature type hints
ooloth Nov 22, 2025
7745fcf
claude(skills): add a few mypy rules
ooloth Nov 22, 2025
a7dede8
claude(skills): parse more completely at I/O boundary
ooloth Nov 22, 2025
e71e44a
claude(skills): parse more completely at I/O boundary
ooloth Nov 22, 2025
77e8b95
claude(skills): rename first words to gerund form (e.g. "scan" -> "sc…
ooloth Nov 22, 2025
57816c7
claude(skills): update a couple more references to the new names
ooloth Nov 22, 2025
aacdee6
claude(skills): list pydantic as a dependency
ooloth Nov 22, 2025
dc18f49
claude(drafting-til): update based on notion posting errors it encoun…
ooloth Nov 22, 2025
68ebdd0
claude(scanning-git-for-tils): move tests into subfolders
ooloth Nov 22, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
384 changes: 384 additions & 0 deletions .claude/specs/til-workflow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,384 @@
# TIL Workflow Spec

This spec documents a workflow for Claude to suggest and draft TIL-style blog posts based on conversations, git history, and Notion content.

## Goals

- Enable Claude to organically suggest TIL topics during conversations
- Provide explicit commands to scan for TIL opportunities
- Draft TILs in the user's voice with proper Notion formatting
- Keep Claude's drafts clearly separated from user's content

## Non-Goals

- Auto-publishing (user always reviews and publishes)
- Editing existing user content (Claude only creates new pages)
- Complex multi-part blog posts (TILs only)

---

## Architecture

### Skills (in `~/.claude/skills/`)

```
skills/
scanning-git-for-tils/
SKILL.md
scan_git.py
scanning-notion-for-tils/
SKILL.md
scan_notion.py
drafting-til/
SKILL.md # Voice guide, format rules, property mappings
```

### Commands (in `~/.claude/commands/`)

```
commands/
suggest-tils.md # Orchestrates the full workflow
```

### Database Changes

Add "Claude Draft" status to Writing database (Status property).

### CLAUDE.md Addition

Add organic trigger hint to global CLAUDE.md.

---

## Writing Database Schema

**Database URL**: `https://www.notion.so/eb0cbc7a4fe4495499bd94c1bf861469`
**Data Source ID**: `c296db5b-d2f1-44d4-abc6-f9a05736b143`

### Key Properties for TIL Creation

| Property | Type | TIL Value |
| ----------- | ------------ | ---------------------------------- |
| Title | title | The TIL title |
| Status | status | "Claude Draft" (new status to add) |
| Type | select | "how-to" |
| Destination | multi_select | ["blog"] |
| Description | text | One-line summary |
| Slug | text | URL-friendly version of title |
| Topics | relation | Link to relevant Topics |
| Research | relation | Link to source Research items |
| Questions | relation | Link to source Questions |

### Status Options (existing)

- New, Researching, Drafting, Editing, Publishing, Published, Paused, Migrated to content repo, Archived

**Add**: "Claude Draft" (in to_do group, distinct color like orange)

---

## Voice Guide

### Source Material Analyzed

1. **Notion post**: "The filter(Boolean) trick" - ~500 words, detailed how-to
2. **Website post**: "Ignoring files you've already committed" - ~150 words
3. **Website post**: "A '!' prefix makes any Tailwind CSS class important" - ~50 words

### Two TIL Formats

**Ultra-short (50-150 words)**

- Single tip with one code example
- Minimal explanation
- Best for simple gotchas or quick references

**Standard (300-500 words)**

- Problem β†’ bad solution β†’ good solution structure
- Multiple code examples
- More explanation and personality
- Best for concepts that need unpacking

### Voice Characteristics

1. **Direct titles** - State exactly what the reader will learn
- Good: "The filter(Boolean) trick"
- Good: "A '!' prefix makes any Tailwind CSS class important"
- Bad: "Understanding Array Methods in JavaScript"

2. **Problem-first opening** - Start with the issue
- "If you try to `.gitignore` files _after_ committing them, you'll notice it doesn't work"
- "You have an array... But hiding in that array are some unusable null or undefined values"

3. **Conversational tone**
- Use "you" to address reader directly
- Contractions are fine
- Second person throughout

4. **Playful asides and humor**
- "Illegal! Now you're a criminal"
- "Oh noooo..."
- "Really, really no vertical margins"
- Don't overdo it - one or two per post

5. **Code examples always included**
- Show the problem code
- Show the solution code
- Inline comments can have personality

6. **No fluff**
- Get to the point quickly
- Short paragraphs
- Scannable structure

7. **Helpful signoff** (optional)
- "Hope that helps!"

### What NOT to Do

- Don't be formal or academic
- Don't over-explain obvious things
- Don't use passive voice
- Don't add unnecessary caveats
- Don't start with "In this post, I'll show you..."

---

## Skill Specifications

### scanning-git-for-tils

**Purpose**: Analyze recent git commits for TIL-worthy patterns

**Description** (for SKILL.md):

```
Scans git history for commits that might make good TIL blog posts.
Looks for bug fixes, configuration changes, gotchas, and interesting
solutions. Returns a formatted list of suggestions with commit context.
Use when user asks for TIL ideas from their recent work.
```

**What to look for**:

- Commits with "fix" that solved a non-obvious problem
- Configuration changes (dotfiles, CI, tooling)
- Dependency updates that required code changes
- Commits with detailed messages explaining "why"
- Patterns that repeat (user keeps solving same problem)

**Output format**:

```
πŸ“ TIL Opportunities from Git History (last 30 days):

1. **Git: Ignoring already-tracked files**
- Commit: abc123 "fix: properly ignore .env after initial commit"
- Pattern: Removed cached files, updated .gitignore
- TIL angle: Common gotcha - .gitignore doesn't affect tracked files

2. **Zsh: Fixing slow shell startup**
- Commits: def456, ghi789 (related)
- Pattern: Lazy-loaded nvm, deferred compinit
- TIL angle: Diagnose and fix slow shell initialization
```

### scanning-notion-for-tils

**Purpose**: Find unpublished Writing items ready for TIL treatment

**Description** (for SKILL.md):

```
Searches the Notion Writing database for unpublished items that could
become TIL posts. Prioritizes items with Status=New or Drafting,
Type=how-to, and recent activity. Returns suggestions with context.
Use when user wants to review their backlog for TIL opportunities.
```

**Search criteria**:

- Status: New, Researching, or Drafting
- Type: how-to (preferred) or reference
- Has linked Research or Questions (indicates depth)
- Sorted by Last edited (recent activity)

**Output format**:

```
πŸ“ TIL Opportunities from Notion Backlog:

1. **"Make TS understand Array.filter by using type predicates"**
- Status: Drafting | Last edited: 2 months ago
- Has: 2 Research links, 1 Question
- TIL angle: Type predicates let TS narrow filtered arrays

2. **"How to filter a JS array with async/await"**
- Status: New | Last edited: 1 year ago
- Has: 1 Research link
- TIL angle: filter() doesn't await - need Promise.all pattern
```

### drafting-til

**Purpose**: Create a TIL draft in Notion with proper voice and formatting

**Description** (for SKILL.md):

```
Drafts a TIL blog post in the user's voice and creates it in Notion
with Status="Claude Draft". Uses the voice guide for tone and format.
Includes proper property mappings for the Writing database.
Use when user approves a TIL suggestion and wants a draft created.
```

**SKILL.md should include**:

- Complete voice guide (from above)
- Property mappings
- Example TIL structures (ultra-short and standard)
- Instructions for using Notion MCP tools

**Creation process**:

1. Determine appropriate length (ultra-short vs standard)
2. Write title (direct, specific)
3. Write content following voice guide
4. Generate slug from title
5. Write one-line description
6. Create page with properties:
- Status: "Claude Draft"
- Type: "how-to"
- Destination: ["blog"]
- Topics: (link if obvious match)
- Research/Questions: (link to sources)

---

## Command Specification

### /suggest-tils

**Purpose**: Orchestrate the full TIL suggestion and drafting workflow

**Workflow**:

```
Phase 1: Source Selection
─────────────────────────
Which sources to scan?
1. Git history (last 30 days)
2. Notion backlog
3. Both
>
```

```
Phase 2: Scan Results
─────────────────────
[Invoke appropriate skill(s)]
[Display combined suggestions]

Select a topic to draft (number), or 'q' to quit:
>
```

```
Phase 3: Draft Creation
───────────────────────
[Invoke drafting-til skill with selected topic]
[Show preview of created page]

βœ… Draft created: "Your TIL Title"
Status: Claude Draft
URL: https://www.notion.so/...

Actions:
o - Open in Notion
e - Edit properties
n - Draft another
q - Done
>
```

**State management**: Use TodoWrite to track workflow phase

---

## CLAUDE.md Addition

Add to global `~/.claude/CLAUDE.md` (symlinked from `tools/claude/config/CLAUDE.md`):

```markdown
## TIL Suggestions

When you help solve a non-trivial problem or explain something in detail,
consider if it would make a good TIL blog post. Look for:

- Gotchas or surprising behavior
- Elegant solutions to common problems
- Things worth documenting for future reference

Suggest naturally: "This could make a good TIL - want me to draft it?"

To scan for TIL opportunities or draft posts, use the `/suggest-tils` command.
```

---

## Implementation Order

1. **Add "Claude Draft" status** to Writing database
- Use `mcp__notion__notion-update-database` to add status option

2. **Create drafting-til skill** first (other skills depend on understanding the output format)
- `~/.claude/skills/drafting-til/SKILL.md`

3. **Create scanning-git-for-tils skill**
- `~/.claude/skills/scanning-git-for-tils/SKILL.md`
- `~/.claude/skills/scanning-git-for-tils/scan_git.py`

4. **Create scanning-notion-for-tils skill**
- `~/.claude/skills/scanning-notion-for-tils/SKILL.md`
- `~/.claude/skills/scanning-notion-for-tils/scan_notion.py`

5. **Create /suggest-tils command**
- `~/.claude/commands/suggest-tils.md`

6. **Add CLAUDE.md hint**
- Update `tools/claude/config/CLAUDE.md`

---

## Safety Rules

These rules prevent Claude from making unwanted edits:

1. **Never edit existing pages** unless explicitly asked
2. **Always use Status="Claude Draft"** for new pages
3. **Show content before creating** - user approves the draft text
4. **Link sources via relations** - don't modify source pages
5. **User publishes** - Claude never changes Status to Published

---

## Testing the Workflow

After implementation, test with:

1. `/suggest-tils` β†’ select "Git history" β†’ verify scan results
2. `/suggest-tils` β†’ select "Notion backlog" β†’ verify scan results
3. Select a suggestion β†’ verify draft created with correct properties
4. Check Writing database filtered by Status="Claude Draft"
5. Organic test: Solve a problem, see if Claude suggests TIL

---

## Future Enhancements (Out of Scope)

- Browser history scanning
- Slack conversation scanning
- Automatic topic detection/linking
- Draft quality scoring
- Publishing workflow automation
Loading