Back to Blog

Building an Editorial Workflow with GitHub and Slack

John Jeong

John Jeong

We recently rebuilt our entire editorial workflow from scratch.

Not a tweak. A complete rebuild.

And the question we kept getting was: "Why didn't you just use Payload? Or Sanity? Or any of the existing CMS products?"

The answer goes deeper than "we wanted more control." It connects to something we've been thinking about since we started Hyprnote: the belief that content should live as files, not database rows.

This is Part 7 of our publishing series, and it's probably the most philosophical one. We'll explain the "why" first, then break down exactly what we built.

The Filesystem Is the Cortex

We wrote about this in The Filesystem Is the Cortex, but the core thesis is simple:

Files are a human interface, not a technical detail.

Humans have organized information spatially for centuries. Drawers. Cabinets. Folders. We remember where something is. Location is recall. Structure is memory.

When notes—or blog posts—live as files, they feel like part of you. When they live as opaque blobs behind an API, they feel like someone else's product.

This isn't nostalgia for "old-school files." It's a belief about the future:

If AI is going to help humans think, it needs access to artifacts humans can own, inspect, move, and understand.

Markdown. Plain text. Files.

The filesystem is the cortex—and in the AI era, it becomes even more important, not less.

Why Not Payload, Sanity, or Other CMS Products?

We evaluated them all. Payload is excellent. Sanity is powerful. But every CMS we looked at had the same fundamental issue:

They want your content to live in their system.

Even the "open source" ones. Even the "self-hosted" ones. Your content becomes structured JSON in a database, mediated through schemas, accessed via APIs.

That's fine for some use cases. But for us, it violated the core principle:

Content should be files. Files in a repo. Diffable. Portable. Ownable forever.

We already wrote about this in Why Our CMS Is GitHub. GitHub gives us everything a CMS promises—versioning, collaboration, review workflows, rollback—without the lock-in.

But there was one gap: editorial workflows for non-engineers.

The Gap We Needed to Fill

Our stack was simple: MDX files in GitHub. Engineers write in IDEs. PRs are drafts, merges are publish.

But we hit friction:

  1. Accidental publishes — No review gate. Click merge, it's live.
  2. Lost work — Writers forgot to save. Changes disappeared.
  3. No visibility — What's pending? What's been reviewed? Nobody knew.
  4. Context switching — Reviewers had to check GitHub constantly.
  5. No unified actions — Approve in GitHub, notify in Slack, merge somewhere else.

We needed an editorial workflow. But we didn't want to abandon our file-first principles.

So we built one.

What We Built

The system has three layers:

1. Draft PRs by Default

Every change—new post, edit, unpublish—creates a draft pull request.

Draft PRs are GitHub's best-kept secret. They:

  • Don't notify reviewers
  • Don't show up in review queues
  • Signal "I'm still working on this"
  • Can be converted to "ready for review" with one API call

When a writer creates a new post, it lives on a draft PR. They can edit, save, walk away, come back. The PR stays invisible until they're ready.

2. Auto-Save with Visible Countdown

Writers shouldn't lose work. But they also shouldn't be interrupted.

We added a 60-second auto-save countdown:

[ Save (52s) ]

When the countdown reaches zero:

  • Content auto-saves to the draft PR branch
  • No tab opens. No notification. Silent.
  • The countdown resets if more changes are made

Manual save (button or Cmd+S):

  • Saves immediately
  • Countdown disappears
  • Still no tab opens—saving is silent

The PR URL only opens when submitting for review. This keeps writers focused on writing, not on managing PRs.

3. Slack as the Review Interface

Reviewers live in Slack. So Slack became our review interface.

When a writer clicks "Submit for Review":

  1. Content saves with published: true
  2. Draft PR converts to ready-for-review
  3. Reviewer is automatically assigned
  4. Slack receives a notification with three buttons:
┌─────────────────────────────────────────────────────────────┐
│ Article submitted for review                                │
│ @john please review                                         │
│                                                             │
│ > "Building an Editorial Workflow with GitHub and Slack"    │
│                                                             │
│ [ Preview ]  [ View PR ]  [ Merge ]                         │
└─────────────────────────────────────────────────────────────┘
  • Preview — Opens the Netlify deploy preview
  • View PR — Opens GitHub for detailed review
  • Merge — Merges the PR directly from Slack

One click. Article goes live.

For unpublishing, we send a yellow warning message:

⚠️ @jane wants to unpublish "Article Title"

Destructive actions deserve visual distinction.

The Technical Stack

Everything is built on primitives that already exist:

ComponentImplementation
Content storageMDX files in GitHub repo
Draft workflowGitHub draft PRs
Auto-saveReact state + interval + GitHub API
PR conversionGitHub REST API (PATCH /pulls/{id})
NotificationsGitHub Actions + Slack API
Merge from SlackSlack interactive webhook → GitHub API
PreviewNetlify deploy previews (automatic)

No database. No CMS backend. No proprietary schemas.

Just GitHub, Slack, and a few hundred lines of glue code.

Button States: Small Details Matter

Getting button states right is crucial for clarity:

ScenarioSaveSubmit for ReviewStatus
No unsaved changesDisabledDisabledCurrent state
Has unsaved changesEnabled + countdownEnabledCurrent state
Currently savingSpinnerDisabledCurrent state
Unpublished articleGray "Not Published"
Published articleGreen "Published" (hover: "Unpublish")

Writers don't need a "Publish" button. They need to know if something is published. Make state visible; make actions secondary.

Why This Matters for Open Source

Here's where it gets interesting.

We're an open source company. Hyprnote is open source. And we believe this editorial workflow should be open source too.

Not just "source available." Actually usable by other teams.

The vision:

Bring your own repository. Bring your own S3. Get a complete editorial workflow.

Imagine a world where:

  • Your content lives in your GitHub repo (not ours)
  • Your images live in your S3 bucket (not ours)
  • You get draft PRs, auto-save, Slack notifications, one-click merge
  • Zero vendor lock-in. Zero data migration. Forever portable.

This is the opposite of what CMS products offer. They want you to put content in their system. We want to give you tools that work with the systems you already have.

We're not there yet. But the architecture is designed for it. The code is written to be extractable. And we're committed to open sourcing it when it's ready.

What We Learned

1. Draft PRs are criminally underused

Most teams create regular PRs immediately. Draft PRs are better for work-in-progress because they don't spam reviewers with notifications.

2. Auto-save needs visibility

Silent auto-save creates anxiety. "Did it save? Should I save manually?" A visible countdown removes uncertainty.

3. Slack is a legitimate review interface

For simple approve/reject workflows, Slack buttons are faster than GitHub's UI. Save GitHub for complex reviews with inline comments.

4. Status indicators matter more than action buttons

Writers don't need a "Publish" button. They need to know if something is published. Make state visible; make actions secondary.

5. Files are the foundation

Every design decision was easier because we started with files. No schema migrations. No content lake. No API rate limits. Just files.

The Philosophy Behind It

We built this because we believe:

  1. Content should be owned, not rented. Your words should live in your repo, not in a SaaS database.

  2. Tools should compose, not capture. GitHub + Slack + Netlify already exist. We connected them instead of replacing them.

  3. Simplicity survives. Markdown files will outlive every CMS platform launched this decade.

  4. Open source means open data. If the software is open, the content should be portable.

This editorial workflow is one piece of that vision. It's how we publish our blog, our docs, our changelog. And eventually, it's something we want to share with every team that believes content should be files.


This is Part 7 of our publishing series.

  1. Why We Write Our Blog in an IDE
  2. Why Our CMS Is GitHub
  3. Choosing a CMS in 2025
  4. Don't Use a CMS Until You Absolutely Need One
  5. Docs Edition: What to Use for Developer Documentation
  6. How We Built Hyprnote's Publishing Stack
  7. Building an Editorial Workflow with GitHub and Slack (You are here)
Hyprnote

Try Hyprnote for yourself

The AI notepad for people in back-to-back meetings. Local-first, privacy-focused, and open source.