Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions .agents/skills/contribute-blog/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
---
name: contribute-blog
description: >-
Create, import, edit, or review posts for the
official Flutter blog at flutter.dev/blog,
including metadata, media, authors, and publication checks.
---

# Contribute to the Flutter blog

## Editorial approach

Preserve the author's voice, intent, and requested scope.
First person, contractions, anecdotes, humor, enthusiasm,
and future-facing announcements can all be appropriate.
Don't rewrite them merely to match documentation conventions.

Apply `write-technical-docs` and `format-markdown` selectively for clarity,
accuracy, accessibility, links, code formatting, and sound structure.
Their documentation-specific preferences aren't blanket blog requirements:
semantic line breaks and an 80-character limit aren't required,
especially when importing or lightly editing an existing post.

Fix or flag substantive issues with source fidelity,
technical accuracy, accessibility, metadata, or rendering.
Treat preference-only rewrites as suggestions
unless copyediting was requested.

## Read relevant reference material

- For a new post, import, metadata or media change,
structural edit, or full review, read
[Flutter blog post format](references/post-format.md).
- For a Google Doc import, also read
[Import from Google Docs](references/google-doc-import.md).
- To add or update an author or resolve an unknown author ID, read
[Manage blog authors](references/authors.md).

A small prose-only correction might need no reference.
Consult `sites/www/content/blog/data.yaml`,
`sites/www/content/blog/authors.yaml`, comparable recent posts,
or implementation source when a convention is unclear.

## Code and quality checks

- If changing or writing Dart or Flutter samples,
apply `write-dart` and `write-flutter` as relevant.
Validate complete examples when practical and
label intentional omissions or pseudocode clearly.
- Before calling a post ready,
search the changed content for unresolved markers and placeholders,
such as `TODO`, `TBD`, or placeholder notes.
Report intentional markers or blockers instead of silently removing them.

## Validate proportionally

For a new post or a change to metadata or content,
run the build and link-reference checks:

```bash
dart run dash_site --site=www build
dart run dash_site --site=www check-link-references
```

When layout, media, metadata, or content significantly changes,
consider previewing the site locally:

```bash
dart run dash_site --site=www serve
```

For a prose-only edit that doesn't change links,
direct inspection of the content can be enough.
70 changes: 70 additions & 0 deletions .agents/skills/contribute-blog/references/authors.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Manage blog authors

Use this reference when adding or updating an author,
or when a post's author ID doesn't resolve.

Authors are defined in `sites/www/content/blog/authors.yaml`, and
their local profile images live in `sites/www/content/blog/author_images/`.

The top-level key in `authors.yaml` is a stable content ID,
not necessarily the author's current social handle.

## Add or resolve an author

Before adding a record,
search `authors.yaml` by ID, display name, and profile URL.
Use verified or author-provided details.
Don't invent a name, profile, or image.
For a new ID, choose a recognizable lowercase handle or concise stable slug,
then insert the record alphabetically by ID.

`name` is required while `image`, `imageUrl`, and `link` are optional:

```yaml
author-id:
name: "Author Display Name"
image: "author-id.webp"
link: "https://github.com/author-id"
```

- `image` names a local image file in `author_images/`.
- `imageUrl` accepts an external URL to use as a fallback to `image`.
Prefer a local `image` over setting `imageUrl`. Don't set both.
- `link` is the destination linked from the byline. Prefer their GitHub profile.

## Author images

Name a local image after the exact author ID and
use its real lowercase `.jpg` or `.webp` extension,
such as `author-id.webp`.
Optimize it for a small square display and a centered circular crop.
Use an author-supplied or appropriately reusable image.

## Update an author

Keep the existing ID when an author's name, handle, link, or image changes.
If the ID must change, update every occurrence in post frontmatter.

When replacing an image with a different filename or extension,
search for references to the old file before removing it.
Don't remove an apparently unused author without checking all posts.

## Configure the authors of a post

In a post's `index.md` frontmatter:

For a single author, use a YAML scalar:

```yaml
author: author-id
```

For multiple authors, use an ordered list:

```yaml
author:
- first-author
- second-author
```

List order controls the displayed byline.
99 changes: 99 additions & 0 deletions .agents/skills/contribute-blog/references/google-doc-import.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# Import from Google Docs

Use this reference to convert an authored Google Doc into a Flutter blog post
without turning the import into an unsolicited rewrite.

## Get the source

First, try to download the source yourself.
Open the document in an authenticated browser and choose
**File > Download > Web Page (.html, zipped)**.
An authenticated Google Docs or Drive connector is also suitable
if it can produce the complete HTML export and original media.

If you can't access the document, the download fails,
or the export is incomplete,
ask the user to download and provide the HTML zip.
Don't reconstruct content that the available source omits.

Import the document body as exported.
Ignore comment threads and suggestion metadata,
don't reproduce or act on them.
Extract exports into a temporary directory and
don't commit the source archive or intermediate conversion files.

## Convert content, not export debris

Preserve the document's structure and meaning,
including headings, prose, lists, tables, emphasis, links,
code, images, and captions.
Convert ordinary content to clean Markdown,
using site components when they provide necessary behavior.

Strip Google Docs export artifacts:

- **Redirects**:
Replace Google redirect and tracking URLs with their direct destinations.
- **Styling spans & non-breaking spaces**:
Remove non-relevant markup and structure, such as
inline CSS, font declarations, classes, empty anchors, and wrapping spans.
- Replace ` ` with standard whitespace.
- **Code snippets**:
Convert exported code to fenced Markdown blocks
with appropriate language identifiers, such as `dart` or `bash`.
Google Docs might represent code as `<p>` tags with
`&nbsp;` indentation or as single-cell tables.
- **Titles**:
Don't replicate the document title as an `# H1` heading in the Markdown body.
The `title` in the post's frontmatter supplies the page H1.
- **Footnotes**:
Preserve footnote content,
but omit generated Google Docs anchor navigation links.
- **Videos**: Convert standalone YouTube links into `<YouTubeEmbed>` components.

Keep the author's person, tone, pacing, spelling variety,
heading style, and rhetorical choices unless editing was requested.
Correct conversion errors,
but surface optional prose changes separately.

## Resolve authors

Identify the ordered authors from an explicit byline or user context,
not from document ownership or editor metadata.

To resolve their IDs and configure the post's frontmatter,
follow the steps in [Manage blog authors](authors.md).
If the source lacks enough information to identify or resolve an author,
ask the user for their GitHub or other profile URL.

## Reconcile images

Map each exported image to
its source position, caption, and purpose
before renaming or moving it:

- Place images in the post's `images/` directory
with concise, descriptive names.
- Keep the highest-quality intended source.
Convert static raster images to WebP when quality and clarity are preserved.
- If the image is a JPEG, prefer a `.jpg` extension over `.jpeg`.
- Preserve intentional animation
and provide a static `socialImage` when needed.
- Follow the alt text and `<DashImage>` guidance in
[Flutter blog post format](post-format.md).
- If an image's purpose or placement is ambiguous,
ask for guidance rather than guessing.

## Check fidelity

Compare the converted post with the source section by section.
Confirm that no prose, list item, code block, table row, image, caption,
footnote, or intended link is missing or misplaced.
Check heading hierarchy, link destinations, image-caption pairings,
and meaningful emphasis.
Report any placeholder or editorial hold in the document body
that prevents the post from being ready.

Finish with the format and accessibility checks in
[Flutter blog post format](post-format.md)
and the validation workflow in the [parent skill](../SKILL.md).
Loading
Loading