[ COPY & CONTENT · OPERATOR UTILITY ]
/pb-post
Create a Vacca/ColdIQ-grade LinkedIn post for Faris's personal brand (faris-bio) — a dark, information-rich infographic (static PNG + animated GIF) plus brand-voice copy and a pinned comment with a proof image.
ACME Agency, <id> and you@example.com mark values that are per-agency — your install fills them with YOUR clients and accounts. If a section references a helper script you don't have yet, it ships with that workflow's install./pb-post — faris-bio LinkedIn post engine
Produces a complete, post-ready LinkedIn asset in the ColdIQ / Alex Vacca visual language, but in Faris's brand and voice. The differentiator vs. AI image tools: the graphic is hand-coded HTML/CSS rendered to PNG/GIF by Chromium, so every label is pixel-sharp and every number is real. Krea is only ever used for a text-free atmospheric backdrop (the hero style), never for text.
When to trigger
"make me a LinkedIn post", "pb-post", "post about X", "turn this into a LinkedIn graphic/carousel", "a Vacca-style post about Y". English only.
Output — ALWAYS a proposed/ folder
Everything for one post goes in one self-contained folder so it can be ACME Agencywed/handed off:
faris-bio/channels/linkedin/proposed/<YYYY-MM-DD-slug>/
post.md # the body copy
pinned-comment.md # pinned comment text (+ which image to attach)
checklist.md # the little-elements check, all ticked
visual.gif # the post asset (animated — POST THIS)
visual.png # static fallback
pinned-comment-image.png# proof shot / secondary image for the comment
Never scatter a post across posts/ + assets/ again — one proposed folder per post.
Styles (pick or let the user choose)
- grid (default) — dense 2-column category grid, real tool logos + numbered badges, center Claude-orange hub, animated dots. Best all-rounder. Engine:
faris-bio/scripts/<id>.mjs. - hero — AI (Krea) text-free glowing orb backdrop + code cards/text on top + glowing curved connectors. Most cinematic. Engine:
<id>.mjs(+<id>.mjs --backdropfor the orb). - radial — central hub + nodes on connector lines. Engine:
render_claude_stack.mjs --layout radial. - terminal-proof — a real
ls-style terminal (proof shot). Engine:<id>.mjs. Also the default pinned-comment image. - funnel — top-to-bottom stacked stages that narrow (funnel silhouette), heat rising, animated flow chevrons. For anything sequential/staged (e.g. a full-funnel system). Engine:
render_pb_funnel.mjs.
New styles are welcome — add a render script and document it here.
Color rule: Claude brand orange (#D97757) is reserved for posts about Claude Code (the title highlight + center logo). For any other topic, use faris-bio blue (#5BA3F5) for the highlight. Category/stage colors are free.
Pipeline
- Get the topic + the real facts. Never invent numbers. Confirm team size, client count, metrics with Faris. Pull skill/agent counts live from
.claude/skills+.claude/agents(the terminal-proof script does this). - Write the copy in Faris's voice — delegate to the
copywriteragent withfaris-bio/brand/voice.mdas reference. Structure: number/claim hook → reframe → numbered list mirroring the visual's sections → one napkin-math moment → one honest-about-fails line → one "don't do X" line → single ask ending in a question. Then a pinned comment (full detail + a link/proof).
LinkedIn packaging (readability — always apply): the copy must be scannable, like Charlie Hills / Jasmin Alić posts.
- One idea per line. Never a dense multi-sentence paragraph. Max 1-2 lines per block.
- Blank line between every block (LinkedIn eats single newlines; double them).
- Hook = the first 2 short lines — they must land before LinkedIn's "…more" cutoff. No throat-clearing.
- Numbered list that mirrors the visual's stages/cards: each item is a short label line, then ONE supporting line under it.
- No markdown bold (
**) — LinkedIn renders it literally. Use a bare label line or CAPS for emphasis. - Emoji: at most one, functional (e.g. a 👇 on the comments line). Usually none. Never decorative.
- Length: aim ~120-180 words. Shorter is better. Cut every line that does not teach.
- End with: one CTA question, then an optional short P.S. (great home for the "don't do X" / credibility line).
- Pinned comment: same short-line treatment — numbered, label + one line, the exact commands/tools, one rule, and the YouTube handle.
- Render the visual with the chosen style's script → PNG + GIF.
- Render/choose the pinned-comment image (default: terminal-proof).
- Assemble the
proposed/<slug>/folder (copy assets in, write post.md + pinned-comment.md + checklist.md). - Verify against the checklist below before declaring done. Regenerate anything that fails.
The little elements — verify EVERY post (verify-by-default)
Copy of this lives in each post's checklist.md.
Voice (brand/voice.md): number/claim hook · single-sentence paragraphs · one checkable napkin-math moment · one honest-about-fails line · one "don't do X" line · named tools · exactly one ask, ends on a question · NO em-dashes · no banned phrases (unlock, game-changer, in this video, let's dive in…) · no two-word fragments.
Facts: real and checkable · identical across copy + visual + proof image · skill/agent counts match ls .claude/skills.
Identity: name = "Faris Biogradlić" (never "faris-bio") · tagline set, no "@faris-bio" handle in the body · real headshot in avatar (brand/visual-identity/headshot.png).
Visual: Claude orange for the "CLAUDE CODE" highlight + center logo, faris-bio blue (#5BA3F5) for personal-brand chrome · real tool logos (favicons via fetch_brand_icons.mjs) on 3rd-party items, terminal glyph on own /skills · pixel-sharp code-rendered text (never an AI image for text) · motion actually works (GIF frames differ — animated GIF is ~1MB, a static one is ~330KB; if it's tiny, the animation didn't render) · seamless loop.
Comment: pinned comment written · proof/secondary image attached.
Assets & helpers
- Brand voice:
faris-bio/brand/voice.md· tokens:brand/visual-identity/tokens.json - Headshot:
brand/visual-identity/headshot.png(auto-used when present, else "FB" monogram) - Tool logos:
brand/visual-identity/icons/*.png(refresh withscripts/fetch_brand_icons.mjs) - Render scripts:
faris-bio/scripts/render_claude_stack_*.mjs,<id>.mjs
Gotcha (learned)
The GIF animation must be gated on an animated flag passed to the HTML builder, and set TRUE for the frame-capture loop (not on a --video CLI flag the GIF path never sets) — otherwise every GIF frame is identical and the post is silently static. Confirm motion by checking the GIF file size (~1MB) or diffing two frames.