/ Content
In the previous post, I covered the Folio-based blog setup I use on marketing sites. The short version: blade files in a directory are routes, each post has a @post-meta comment block, and the index page scans the directory to build the listing automatically.
The part I left out was how I actually create posts. The file structure is easy to work with, but there's boilerplate in every post: the meta section, the canonical URL, the OG tags, the JSON-LD schema. I want to write the content, not format the file by hand each time.
My solution is a GitHub issue form that feeds directly into a Copilot workflow. Here's how it works.
GitHub Issue Templates
Issue templates live in .github/ISSUE_TEMPLATE/ in your repo. The YAML format lets you define a form with specific fields instead of a blank text box.
name: Blog Post
description: Submit a new blog post
title: "[Blog Post]: "
labels: ["new blog post"]
assignees:
- copilot
body:
- type: input
id: title
attributes:
label: Post Title
validations:
required: true
- type: textarea
id: content
attributes:
label: Post Content
description: Markdown, HTML, or plain text
validations:
required: true
- type: input
id: date
attributes:
label: Publish Date
description: "Format: MM/DD/YYYY"
validations:
required: true
When someone creates an issue using this template, GitHub renders it as a proper form. Fill in the fields, submit, and the issue is created with the label new blog post applied automatically. No label selection required, no formatting to remember.
The submitted issue body is structured too. Each field shows up under a ### Field Name heading, which makes it easy to parse programmatically.
The Workflow
A GitHub Actions workflow watches for the label and fires when it's applied:
on:
issues:
types: [labeled]
jobs:
assign-to-copilot:
if: github.event.label.name == 'new blog post'
runs-on: ubuntu-latest
steps:
- name: Assign issue to Copilot
uses: actions/github-script@v7
with:
github-token: ${{ secrets.COPILOT_ASSIGN_TOKEN }}
script: |
// extract fields from issue body, then...
await github.request(
'POST /repos/{owner}/{repo}/issues/{issue_number}/assignees',
{
assignees: ['copilot-swe-agent[bot]'],
agent_assignment: {
base_branch: 'main',
custom_instructions: `...`,
},
}
);
The workflow parses the issue body to pull out the title, description, content, and publish date. Then it calls the GitHub API to assign the issue to copilot-swe-agent[bot] with an agent_assignment payload. That payload is what activates the agentic mode, it's not a regular issue assignment.
The Custom Instructions
The custom_instructions string is where the real work happens. This is what Copilot reads to understand the task. Mine includes:
- Where blog posts live (
resources/views/blog-posts/) - How to choose a slug and verify it doesn't already exist
- The exact blade file structure (base component, meta section, post-meta comment block, article content)
- Which meta tags to generate and how
- What JSON-LD schema to use and what values go where
- How to map the raw issue content to the right Tailwind classes
- What PR title to open with
The instructions reference the existing posts in the repo and tell Copilot to read them to match the structure precisely. In practice, Copilot reads a few of the existing files, infers the pattern, and gets the output right.
What You Get Back
A few minutes after submitting the issue, Copilot opens a PR. The PR contains a single new blade file with:
- The canonical URL, meta description, OG tags, and Twitter card tags
- A
BlogPostingJSON-LD schema - The
@post-metacomment block with the correct date and an estimated read time - The post content reformatted to match the project's Tailwind classes
I review the diff, check the rendered post in a local branch if the content is tricky, and merge. The index page picks it up automatically on next load.
Why This Works
The issue template removes the formatting burden. You're not thinking about blade syntax or meta tag structure, you're writing content. The form collects exactly what's needed and nothing else.
The workflow translates that into an agentic task with a single, detailed set of instructions. Copilot has enough context from the existing codebase to produce output that matches without you having to babysit it.
The only manual step is reviewing the PR. For content I trust, that's a 30-second scan. For posts with complex formatting I'll read it more carefully, but the structure is almost always right.
If you're already running a Folio-based blog, the two pieces from these posts, the auto-populating index and the Copilot workflow, are independent. You can add either one without the other. But together they get you pretty close to a zero-maintenance blog that you can publish to from anywhere you can open a GitHub issue.