Add chappe wrapped: shareable PNG dashboard with growth-loop attribution#2
Merged
Conversation
`chappe wrapped @channel --period 90d [--lang en|ru] [--out PATH]` reads the local store, computes channel stats (posts, comments, mean forward-rate, best format, top 3 by forwards, sample audience question), and writes a 1080x1350 PNG card plus a ready caption .txt. The PNG carries 'generated by chappe · github.com/crimeacs/chappe' in the footer, so each post published from it is a quiet referral. Wired into onboarding: - bootstrap fastest_path_to_value now suggests `chappe wrapped` once a channel has ≥20 local posts. The 'why' explicitly frames it as a free engagement post. - onboard setup_steps appends a publish_wrapped_dashboard step at the end of analyze_growth. This makes the first reachable payoff after a fresh sync a tangible image the operator can post immediately, not just JSON. The Chappe attribution turns each adopter's first post into a growth loop. - new dashboard.py: pure rendering (Pillow) + compute_dashboard_stats + bilingual render_caption; tolerates missing Cyrillic glyphs by falling back through a font-path candidate list (Arial → DejaVu) - new pyproject dep: Pillow>=10 - new cli command `wrapped` and two new onboarding steps - 3 new tests: png magic bytes + caption file + sync next_command on unsynced + bootstrap surface for the new fastest-path step
The first cut was a generic dark stats card. This rewrites the renderer as a vintage-dispatch poster that pairs the Chappie mascot with the channel's strongest post as a pull-quote, sits on cream paper with deterministic noise, and prints in a strict 3-ink palette (forest green, sepia, cream). Visual moves - Mascot is the hero. _load_mascot_keyed() alpha-keys the near-white sky in the source illustration so Chappie sits directly on the paper instead of inside a hard rectangle. - Mascot rotates per channel via deterministic seed (channel handle hash), picking from chappie-recorder, signal-operator, lookout, night-watch, or scout-map-reader. Same channel always renders the same mascot. - Channel name in Baskerville Bold (true upright weight via display_bold font role), not Hoefler Black Italic which is what serif_black resolves to on macOS. - Pull-quote from the #1 post by forwards in serif Regular, with a faint oversized opening quote ornament so the quote teases without competing with the masthead. - Two feature stats below the quote: top-post forwards and the channel's mean forward rate. - Bottom ledger is four numeric cells with a consistent rhythm (posts, comments, questions, peak views) plus thin vertical separators. - Footer attribution + monospaced URL. Stats fixes - _best_question() now ranks comment questions by reactions then length, filtering out trivially short ones. Lands on substantive questions instead of the first ?-ending fragment in the corpus. - compute_dashboard_stats() distinguishes most_used_format (count) from best_format_by_lift (forward rate). The visual no longer surfaces the bare 'photo' label; the caption shows both axes. - New peak_views and peak_forwards rollups. Assets shipped in src/chappe/assets/ so they ride along in the wheel: chappie-recorder.png, chappie-signal-operator.png, chappie-lookout.png, chappie-night-watch.png, chappie-scout-map-reader.png.
crimeacs
added a commit
that referenced
this pull request
May 19, 2026
User-facing additions since 0.1.2: - chappe compare @ch1 @ch2 [...]: cross-channel leaderboard with mean forward-rate leader and raw-metric winner. PR #1. - chappe wrapped @channel: PNG channel-dashboard renderer plus caption template with Chappe footer attribution; mascot rotates per channel and Pillow renders cream-paper letterpress style. Onboarding now surfaces it as the first reachable payoff once a channel has ≥20 stored posts. PR #2. - New Pillow>=10 dependency. - Bundled five Chappie mascot illustrations inside the wheel.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
chappe wrapped @channel --period 90d [--lang en|ru] [--out PATH]that renders a 1080×1350 PNG dashboard for the channel plus a ready caption template.Why
Today the first real payoff after onboarding is JSON in a terminal. That's good for agents, but it's not something the operator can immediately turn into a post.
chappe wrappedcloses that gap: 1 command after sync → a finished image + finished caption, ready to publish. Three things compound on that:Visual
1080×1350 vertical card, dark theme. Header (channel + period) → 3 big stat tiles (posts, comments, mean fwd/views) → top 3 posts by forwards with id, views, forwards → best-format + sample audience question → footer with Chappe attribution and the repo URL. Cyrillic renders correctly via Arial / DejaVu fallback.
Onboarding wire-up
bootstrapfastest_path_to_valuenow surfaces arender_wrapped_dashboardstep once the channel has ≥20 local posts. Thewhyfield is explicit about the growth loop ('free engagement post that quietly credits Chappe').onboardsetup_steps.analyze_growthis followed bypublish_wrapped_dashboard.Output shape
{ "ok": true, "channel": "@nn_for_science", "period": "90d", "lang": "ru", "png_path": "/path/to/nn_for_science-90d.png", "caption_path": "/path/to/nn_for_science-90d.txt", "caption_preview": "📊 chappe-wrapped: @nn_for_science · 90d ...", "stats": { "posts": 48, "comments": 921, "mean_forward_rate": 0.01464, "best_format": "photo", "top_posts": [...], "sample_question": "..." }, "next_commands": [ "chappe draft create @nn_for_science --file <caption.txt>", ... ], "growth_hint": "Post this PNG + caption to your own channel..." }Test plan
pytest -q— 41 passed (3 new for wrapped + the existing 38)ruff check src/ tests/— cleanwrappedon an unsynced channel fails with NOT_FOUND and an explicitchappe sync <ch>next_commandbootstrap --channel @chafter 20 stored posts surfaces the newrender_wrapped_dashboardstep infastest_path_to_valueKnown limitation
Pillow does not render color emoji glyphs. A '🤖' inside a post's text shows as a placeholder square. Acceptable for v1; can ship an emoji-stripping pre-pass in a follow-up if it becomes a real complaint.
🤖 Generated with Claude Code