Agent notes
- Review GEMINI.md before working—contains project-specific guidance and expectations.
Pre-commit checklist
Before committing any blog post, always run these checks:
- Validate front matter: Ensure
title,date,categories, andlayoutare present and correct. - Check all links: Extract every URL from the post and verify each returns HTTP 200 (or 401 for API endpoints requiring auth). Fix any broken links before committing.
- Verify code blocks: Ensure all fenced code blocks have a language tag and that commands are syntactically valid.
- Check for secrets: Scan the post for API keys, tokens, or passwords. Never commit secrets to version control.
Commit and push workflow
- Always commit and push your changes after completing the pre-commit checklist.
- Branch strategy:
- For new blog posts or significant changes: create a new branch from
main, commit, push, and open a PR. - For minor fixes: commit directly to
mainand push.
- For new blog posts or significant changes: create a new branch from
- Commit message format: Use a concise, descriptive message that explains what changed and why.
- Never force-push to
mainunless explicitly instructed.
Visual and navigation changes
- For any navigation, layout, or CSS change, inspect the rendered page at desktop and mobile widths before publishing, then inspect the live page again after publishing. Build success and HTTP checks do not replace visual verification.
- Navigation markup must be semantic and structurally match its CSS. Links intended as flex or grid items must be direct children of the navigation container, not hidden inside an automatically generated paragraph wrapper.
- Verify the global header, page-level navigation, overflow, wrapping, active states, and mobile menu behavior on every page type affected by the change.
- If the connected visual browser is unavailable, do not report visual verification as complete. Make the source-level fix, publish a preview, and ask Andrea to confirm the rendering before closing the visual issue.
Creating a new blog post
Blog posts live in the posts/ directory as Markdown files.
File naming
posts/YYYY-MM-DD-slug.md
The slug should be lowercase, hyphenated, and descriptive (e.g., 2026-04-22-deploy-jupyterhub-openstack-magnum-tofu.md).
YAML front matter (header)
Every post starts with a YAML front matter block. Required and common fields:
---
title: "Your concise post title"
date: YYYY-MM-DD
categories: [category1, category2]
---
- title: Always use quotes. Use sentence case, never title case. Capitalize only the first word and proper nouns or acronyms such as ChromeOS and AI. Prefer literal, concrete wording that says what the post helps the reader do. Avoid vague metaphors such as “giving an agent my browser.”
- date: Must match the date in the filename.
- categories: Use existing categories only — do not invent new ones. Common categories:
python,kubernetes,jupyterhub,jetstream,linux,hpc,github,git,openscience,dask,singularity,nersc,sdsc,ai,llm,automation,tools,documentation,events,education,nbgrader,healpy,pysm,cosmology,cloudcomputing,openstack,jetstream2,italian. - description (optional): A one-sentence summary used for SEO and social previews.
- author (optional): Defaults to “Andrea Zonca” via
posts/_metadata.yml. - layout: Set to
postfor blog posts (some older posts omit this). - slug (optional): Override the URL slug if it differs from the filename.
- aliases (optional): Old URLs that should redirect to this post.
Body content and style
- Write in Markdown. The site is built with Quarto using the
literatheme. - Use
##for section headings (the title is rendered separately from the banner block). - Keep an introductory paragraph right after the front matter that summarizes what the post is about.
- Use bullet points and numbered lists for step-by-step instructions.
- Link to relevant resources (GitHub repos, documentation, gists) inline.
- For images, use paths relative to the post’s directory (e.g.,
img/screenshot.png). Avoid absolute paths like/img/.... - Use
---horizontal rules to separate major sections.
Scripts and code
- Multi-line scripts: Upload to a GitHub Gist and embed it in the post:
Also provide a plain-text link to the gist for accessibility.<script src="https://gist.github.com/zonca/GIST_ID.js"></script> - One-liners: Can stay inline in the post body, for example:
curl -o ~/.up.sh https://raw.githubusercontent.com/zonca/up/main/up.sh - Code blocks: Use fenced code blocks with language tags (
```bash,```python).
Categories reference
Only use categories that already exist in the blog. To check existing categories, search the categories: field across files in posts/. Never create new categories unless explicitly instructed.
Publishing workflow
- Create the new post file in
posts/. - Commit and push to the
mainbranch (or open a PR for significant posts). - GitHub Actions renders the Quarto project and publishes to GitHub Pages automatically.
- The Netlify build also triggers on pushes to
main.
Buffer Social Media
Setup
- Buffer skill located at:
/home/zonca/.agents/skills/buffer/SKILL.md - Uses GraphQL API at
https://api.buffer.com - Environment variable
BUFFER_KEYmust be set
Channel IDs (organization: 655270181efd918df3d33eff)
| Platform | Channel ID |
|---|---|
| Twitter/X | 6552702d7a6cf4d23f916d5c |
67c6746b3b85969eafee1ee4 | |
| Bluesky | 67c6738e3b85969eafe22a07 |
Quick post creation
buffer_query() {
curl -s -X POST "https://api.buffer.com" \
-H "Authorization: Bearer $BUFFER_KEY" \
-H "Content-Type: application/json" \
-d "{\"query\": \"$1\"}"
}
buffer_query "mutation { createPost(input: { text: \"POST TEXT\", channelId: \"CHANNEL_ID\", schedulingType: automatic, mode: addToQueue }) { ... on PostActionSuccess { post { id text dueAt } } ... on MutationError { message } } }"
Workflow for new blog posts
- Read the post content
- Draft 1 announcement post adapted for each platform (Twitter: short + hashtags, LinkedIn: professional with bullet points, Mastodon/Bluesky: similar to Twitter)
- Show drafts to user for approval
- Once approved, queue to all 3 channels using Buffer API
Note: If running with Jules, you do not need to do the Buffer social media posting step.