| name | bookclub |
| description | Book club management: generate Slack announcements, reminders, article roundups, eve (day-before + spark questions), one-pagers, and communication timelines. Use when user mentions book club, reading group, book of the month, or wants book-club-related communications or materials. |
Book Club Management
Automate every aspect of running a recurring book club: research books, generate Slack messages, create session materials, and plan communication schedules.
Configuration
Read .claude/bookclub.local.md in the project root if it exists. Parse the YAML frontmatter for the fields below. If the file is missing, use the defaults. Do not block init or generate.
Template to copy: settings-template.md → save as .claude/bookclub.local.md.
| Field | Default (no config file) | Description |
|---|
output_root | . | Root directory; each book is a subfolder <folder_slug>/ with its own book-profile.json and bookclub-* files. Relative paths resolve from the workspace root. |
bookclub_name | (unset) | Full name for branding (e.g. "Digital Science Reads"). See Slack headers below. |
bookclub_short_name | (unset) | Short label for one-pagers or buttons when space is tight. |
slack_channel | (unset) | e.g. #book-club; include in runbooks or timeline notes when useful. |
discussion_venue | (unset) | Default "where / how we meet" line for reminders if not in the book profile. |
organizer_contact | (unset) | Facilitator contact (Slack handle, email). |
timezone | (unset) | IANA timezone for schedule wording when you need explicit TZ context. |
current_book_folder | (unset) | Name of the book subfolder under output_root (e.g. klara_and_the_sun). Required when more than one book folder exists; optional when only one book. |
Per-book layout
Each book has its own directory under output_root:
book_dir = <output_root>/<folder_slug>/
book_profile_path = <book_dir>/book-profile.json
- Generated files (
bookclub-announce.md, bookclub-timeline.json, etc.) live in the same book_dir.
folder_slug (directory name) is derived from the book title at init time:
- Lowercase; replace
& with and.
- Replace any sequence of non-alphanumeric characters with a single
_.
- Trim leading/trailing
_. If the result is empty, use book.
- Collisions: If
<output_root>/<folder_slug>/ already exists and contains a book-profile.json for a different book (different normalized title+author), append _2, _3, … until the path is free or matches the same book (then reuse the folder for re-init).
Resolving book_dir for generate / timeline
- Read config:
output_root, optional current_book_folder.
- If
current_book_folder is set: book_dir = <output_root>/<current_book_folder>; require book-profile.json there.
- Else if
<output_root>/book-profile.json exists and no immediate child directory of output_root contains a book-profile.json: legacy layout; then book_dir = output_root.
- Else: collect each immediate child directory of
output_root that contains book-profile.json. If exactly one, use it as book_dir. If zero, tell the user to run /bookclub:init. If more than one, tell the user to set current_book_folder or pass --book <folder_slug> on the command.
Create output_root and book_dir with mkdir -p before writing when they do not exist.
Slack headers: Prefix announcement-style titles with {bookclub_name} · only when bookclub_name is set to a non-empty value in bookclub.local.md (e.g. *DS Reads · Book of the Month: _{title}_*). If there is no config file or the key is blank, use the template headline without that prefix. For generic copy in documents when no name is configured, you may use the words "book club" in normal sentence case.
When to Use This Skill
Trigger when the user:
- Mentions "book club", "reading group", or "book of the month"
- Asks to generate Slack messages about a book
- Asks for discussion questions or session materials
- Wants to announce, remind, or promote a book reading
- Asks for a QR code, one-pager, or visual summary for a book
- Wants a timeline or schedule for book club communications
- Asks to scrape or look up book data from a URL
Commands
| Command | Description |
|---|
/bookclub:init [title] by [author] | Set up book of the month: research, enrich, create <output_root>/<folder_slug>/, save profile there |
/bookclub:generate [type] | Generate any message or material (optional --book <folder_slug> when multiple books) |
/bookclub:timeline [cadence] | Generate full communication schedule (optional --book <folder_slug>) |
Generate Types
Slack messages (output: Block Kit JSON + mrkdwn):
announce: Book announcement with hook, dates, factoids, links
remind: 1-week-out reading reminder with page count, factoid, purchase link
articles: Related articles/interviews roundup
eve: Day-before reminder plus 3 low-pressure spark questions (default): 1 generic (any book), 1 book-specific (~first half), 1 theme (last). Only use 4 if message stays under 170 words. See slack-templates.md Eve → Question Guidelines
Documents (output: Markdown, optionally PDF with --pdf):
one-pager: Visual summary with QR code
Workflow
1. /bookclub:init "Book Title" by Author Name
→ Researches book, creates `<output_root>/<folder_slug>/`, saves `book-profile.json` there
2. /bookclub:timeline monthly
→ Generates full schedule under that book folder
3. /bookclub:generate announce
→ Writes outputs into the same book folder (repeat for each type as scheduled)
The book-profile.json inside each book folder is the single source of truth for that title. Resolve which folder using config + rules above.
Book Profile
The init command creates a book-profile.json containing:
- Paths:
folder_slug is the directory name under output_root (snake_case from title; set at init)
- Metadata: title, author, author_bio, publication_year, genre, page_count, isbn
- Content: synopsis (paraphrased), themes, factoids, awards
- Links: amazon_de, buch7, medimops, goodreads, publisher, library
- Articles: 3-5 related articles with title, source, url, summary
- Dates: announcement_date, reading_date, discussion_date
- Assets: cover_image_url, qr_target_url
Full schema: references/book-profile-schema.md
Handling Null Dates
If reading_dates fields in book-profile.json are null or missing, derive sensible defaults from today's date:
announcement_date = today
reading_date = 3 weeks from today
discussion_date = 4 weeks from today
Never output "TBD" or leave date placeholders empty. Always show concrete dates.
Slack Message Guidelines
- Tone: Enthusiastic but not cheesy. Smart-casual. The friend who always has great book recommendations
- Structure: Hook -> Body -> CTA. Every message ends with a clear call to action
- Format: Slack mrkdwn (
*bold*, _italic_, :emoji:, > quotes)
- Punctuation in generated copy: Do not use em dashes (—) in member-facing Slack text. Use commas, periods, colons, or parentheses instead (see slack-style-guide.md).
- Length (STRICT hard limits — violations are failures):
- Announcements: 120-220 words
- Reminders: 80-115 words
- Articles roundup: 100-145 words
- Eve: 120-175 words
Count every word in your final output before emitting it. If over the limit, remove words until compliant. URLs count as one word each. Emoji shortcodes (
:emoji:) count as one word each.
- Output only the message: Never append explanations, notes, commentary, or instructions after the message. The output must be the Slack message and nothing else.
- Emoji: 2-4 relevant emojis per message. Prefer: :books: :book: :brain: :bulb: :calendar:
- Links: Use labeled full URLs (one per line) under a :link: section, not
<url|label> mrkdwn, which breaks when copy-pasted outside Slack
Full style guide: references/slack-style-guide.md
All templates: references/slack-templates.md
Timeline Generation
The /bookclub:timeline command produces a full communication schedule for a book club cycle. Output both formats:
- Markdown table with columns: Date, Type, Command, Description. Must have at least 6 rows covering the full cycle.
- Structured JSON in a
```json code block: an array of objects, each with date, type, command, and description fields. Must have at least 6 entries.
Required schedule items (all must appear in both the table and the JSON):
announcement — book reveal
articles — related articles roundup
remind — 1-week-out reminder
eve — day-before spark questions
one-pager — printable summary
discussion — discussion day
When dates are null in the book profile, derive them: announcement = today, articles = 1 week later, remind = 3 weeks later, one-pager = 3.5 weeks later, eve = day before discussion, discussion = 4 weeks from announcement.
Document Generation
One-pagers are generated as Markdown by default. Use the --pdf flag to also produce PDF output via the pdf skill from kjgarza-product.
In one-pager body copy (synopsis, hooks, labels), follow the same rule as Slack: no em dashes (—) in generated member-facing text; prefer commas, periods, colons, or parentheses.
For QR codes on one-pagers, use the Python qrcode library. See references/qr-code-generation.md.
All document templates: references/document-templates.md
Web Scraping
Before using WebFetch on any book URL, check qurl first:
qurl get "<url>"
- Exit 0: content is cached — use it directly, skip WebFetch.
- Exit 1: not cached — proceed with WebFetch, then index:
echo "<fetched_content>" | qurl add "<url>" --source bookclub --tags "<genre>,<language>"
Use --source bookclub on all adds; enables qurl search "query" --source bookclub for lookups across past picks.
When the user provides a book URL or DOM snapshot:
- Use WebFetch to retrieve the page (or parse provided DOM directly)
- Look for JSON-LD structured data and schema.org Book markup first
- Fall back to site-specific CSS selectors (Goodreads, Amazon, etc.)
- Fall back to meta tags (Open Graph, Dublin Core)
- Supplement any missing fields with WebSearch
Scraping patterns: references/scraping-patterns.md
Copyright
- Never reproduce publisher synopses or blurbs verbatim; always paraphrase
- Attribute ratings and awards to their source
- When citing articles, include title, source, and URL
Examples