Skip to main content

Release Shout-out

Transform completed Linear issues/projects into customer-facing release entries for Rondine (publica.la/releases).

Prerequisites

  • RONDINE_API_KEY and RONDINE_API_URL in formica/.env
  • Linear MCP tools available

Quick Commands

# List existing releases
php formica/scripts/rondineHandler.php release list --per_page=10

# Get a specific release by ID
php formica/scripts/rondineHandler.php release get <id>

# Create draft from JSON file
php formica/scripts/rondineHandler.php release create --json=/tmp/release.json

# Update existing release
php formica/scripts/rondineHandler.php release update <id> --json=/tmp/release.json

# Open browser preview for team review
php formica/scripts/rondineHandler.php release preview <id>

# Publish (make visible on public releases page)
php formica/scripts/rondineHandler.php release publish <id>

# Get help
php formica/scripts/rondineHandler.php help

Release JSON Format

Releases have 3 translatable content fields (title, summary, body) plus optional metadata. ALL 7 languages must be generated at draft time.

{
"title": {
"en": "Content File Replacement",
"es": "Reemplazo de archivos de contenido",
"pt": "Substituição de arquivos de conteúdo",
"fr": "Remplacement de fichiers de contenu",
"de": "Austausch von Inhaltsdateien",
"it": "Sostituzione dei file di contenuto",
"pl": "Wymiana plików treści"
},
"summary": {
"en": "Publishers can now replace EPUB, PDF, and audio files directly from the Content Import dashboard.",
"es": "...", "pt": "...", "fr": "...", "de": "...", "it": "...", "pl": "..."
},
"body": {
"en": "<h2>...</h2><p>...</p>",
"es": "...", "pt": "...", "fr": "...", "de": "...", "it": "...", "pl": "..."
},
"is_published": false
}

Linear Label Mapping

Linear LabelRelease Focus
feature, enhancement, newNew feature announcement
improvement, optimization, performanceImprovement/enhancement
bug, fix, bugfixBug fix announcement

Content Templates

New Feature

<h2><strong>A direct, frictionless buying experience — perfect for campaigns, promotions, and more.</strong></h2>

<p>Selling your publications or subscription plans is now simpler than ever. With <strong>Automatic Checkout</strong>, users can go straight to payment from a single link, with no extra steps.</p>

<h2>How it works</h2>
<ul>
<li><strong>Smart detection:</strong> The system checks if the user is logged in and takes the right action</li>
<li><strong>Direct links:</strong> Create URLs that skip the catalog and go straight to checkout</li>
<li><strong>Preserved intent:</strong> Even if login is required, the purchase intent is saved</li>
</ul>

<p>💡 <strong>Result:</strong> Higher conversions and a smoother buying experience.</p>

<p>➡️ <a href="https://help.publica.la/..."><strong>Learn how to set up Automatic Checkout</strong></a></p>

Improvement

<h2><strong>Choose which transactional emails are sent from Publica.la and which ones you manage externally.</strong></h2>

<p>Administrators can now <strong>enable or disable individual email notifications</strong> — such as registration emails, purchase confirmations, or shipping updates — directly from the dashboard.</p>

<p>This update lets you integrate external platforms (like Braze, Customer.io, or custom systems) <strong>without duplicating notifications</strong>.</p>

<h2>What's changing?</h2>
<ul>
<li><strong>Granular control:</strong> Toggle each email type independently</li>
<li><strong>External integration:</strong> Disable Publica.la emails when using third-party platforms</li>
</ul>

<p><strong>Access from:</strong> Dashboard → Settings → Notifications</p>

Bug Fix

<h2><strong>Fixed an issue with EPUB manifest handling that could prevent some books from loading.</strong></h2>

<p>Some EPUB files with specific manifest configurations were not loading correctly in the reader. This has been resolved.</p>

<ul>
<li><strong>Issue:</strong> Certain EPUBs failed to render content when the manifest referenced non-standard paths</li>
<li><strong>Resolution:</strong> The reader now handles all valid manifest formats consistently</li>
</ul>

<p>This fix is now live for all storefronts.</p>

Style Guide

ElementGuideline
ToneProfessional but friendly — like a product team update to customers
OpeningAlways start body with <h2><strong> restating the value proposition in one bold sentence
BoldUse <strong> for feature names, key concepts, and action labels in bullet points
EmojisSparingly — only 💡 (result/takeaway) and ➡️ (CTA/link). Never in titles or summaries
LinksInclude help center link when relevant (help.publica.la). Use ➡️ prefix
Bullet style<strong>Label:</strong> Description — bold label followed by explanation
SectionsUse <h2> for major sections (How it works, What's changing, etc.)
LengthBody: 100-300 words per language. Summary: 1-2 sentences max
FocusWhat the user can now do, not technical implementation details
EndingClose with a 💡 Result line or a practical takeaway

Languages

Every release MUST include ALL 7 languages at draft time:

  1. en — American English (US spelling: "customize" not "customise")
  2. es — Neutral Spanish (no regional variants: no voseo, no argentinisms)
  3. pt — Brazilian Portuguese (pt-BR, not pt-PT)
  4. fr — French
  5. de — German
  6. it — Italian
  7. pl — Polish

The browser preview shows ALL 7 languages with a sidebar for switching between them.

Translation rules

  • Translate the meaning, not word-by-word
  • Adapt idioms and phrasing to be natural in each language
  • Keep the same structure and formatting across all languages
  • Feature names that are proper nouns (e.g., "Automatic Checkout") stay in English across all languages, or use the locally established term if one exists

Cover Image Generation

After creating the release draft, generate a banner image using Gemini's native image generation.

Prerequisites

  • GEMINI_API_KEY in formica/.env
# Generate banner (auto-picks style from release type)
php formica/scripts/geminiBannerHandler.php generate "Feature Title Here" --type=feature --output=/tmp/release_banner.png

# With explicit style
php formica/scripts/geminiBannerHandler.php generate "Title" --type=improvement --style=warm

# List available styles
php formica/scripts/geminiBannerHandler.php styles

Style Presets

KeyNameBest forPalette
boldBold SignalNew featuresDeep navy + electric blue + white
warmWarm EditorialImprovementsWarm cream + amber + dark brown
minimalSwiss MinimalBug fixesWhite + black + red accent
darkDark BotanicalPremium featuresRich dark + emerald + soft white
vibrantCreative VoltageInnovationViolet → fuchsia gradient + white

Type-to-style defaults: feature → bold, improvement → warm, fix → minimal.

Upload to Rondine

After generating the banner, upload it to Rondine's storage and update the release:

# Upload the banner image and get back a public URL
php formica/scripts/rondineHandler.php release upload-cover <id> /tmp/release_banner.png

If upload-cover is not available, manually upload to a public URL and update:

echo '{"cover_image": "https://..."}' > /tmp/release_update.json
php formica/scripts/rondineHandler.php release update <id> --json=/tmp/release_update.json

Workflow Integration

In the main workflow, after step 6 (create draft):

  1. Generate banner: python3 formica/scripts/gemini_banner.py "<en title>" --type <type> --output /tmp/release_banner.png
  2. Upload: php formica/scripts/rondineHandler.php release upload-cover <id> /tmp/release_banner.png
  3. Continue to step 7 (preview)

The cover image appears at the top of both the browser preview and the public release page.

Audience Targeting

Before generating the release, ask the user which audience should see it:

OptionDescription
TodosAll tenants (default — tenant_ids omitted or null)
Tier 1Only tenants with tier = 1
Tier 2Only tenants with tier = 2
Tier 3Only tenants with tier = 3
Sin tierTenants without a tier assigned

Once the user picks an audience (can combine, e.g. "Tier 1 y 2"), query Farfalla to resolve the tenant IDs:

# Tier 1 tenants
echo "SELECT t.id FROM tenants t JOIN sign_up_intents s ON s.tenant_id = t.id WHERE t.deleted_at IS NULL AND s.tiers = 1" | zar farfalla pla:db:query --stdin --json

# Tier 2 tenants
echo "SELECT t.id FROM tenants t JOIN sign_up_intents s ON s.tenant_id = t.id WHERE t.deleted_at IS NULL AND s.tiers = 2" | zar farfalla pla:db:query --stdin --json

# Tier 3 tenants
echo "SELECT t.id FROM tenants t JOIN sign_up_intents s ON s.tenant_id = t.id WHERE t.deleted_at IS NULL AND s.tiers = 3" | zar farfalla pla:db:query --stdin --json

# Tenants without tier
echo "SELECT t.id FROM tenants t JOIN sign_up_intents s ON s.tenant_id = t.id WHERE t.deleted_at IS NULL AND (s.tiers IS NULL OR s.tiers = '')" | zar farfalla pla:db:query --stdin --json

Include the resolved IDs as "tenant_ids": ["123", "456", ...] in the release JSON. If "Todos", omit tenant_ids (null = all tenants).

Workflow

  1. Fetch Linear issue/project context
  2. Ask audience — Todos, Tier 1/2/3, Sin tier (use AskUserQuestion)
  3. Resolve tenant IDs from Farfalla DB if not "Todos"
  4. Generate release JSON with title, summary, and body in ALL 7 languages + tenant_ids
  5. Write JSON to temp file (/tmp/release.json)
  6. Create draft via rondineHandler.php release create --json=/tmp/release.json
  7. Generate banner via geminiBannerHandler.php generate "<en title>" --type=<type>
  8. Upload banner to the release draft via rondineHandler.php release upload-cover <id> /tmp/release_banner.png
  9. Open preview via rondineHandler.php release preview <id> (opens browser with all 7 languages)
  10. Return draft ID + preview URL + Filament admin URL + publish command

Output

The skill creates a draft only (not visible on public releases page).

After creation:

  • A browser preview opens showing all 7 languages with a sidebar for switching
  • The preview has a sticky header with Aprobar (publish) and Rechazar (discard) buttons
  • Publication happens via the preview buttons, Filament admin, or rondineHandler.php release publish <id>

IMPORTANT: Never auto-publish. Always create as draft. Open the preview for team review.