If you work spec-first — writing requirements as reviewable files before writing code — you eventually run into a friction point. Your specs are in the repo. Your issue tracker is somewhere else. And they’re describing the same work in two different places.
For a while, you maintain both. You write a spec, then you write a corresponding issue. When the spec changes, you update the issue. When someone comments on the issue, you update the spec. This is fine for a day or two. After a few weeks, the two representations have drifted, and you can’t tell which one is current.
This is the problem specsync solves.
The idea behind OpenSpec
OpenSpec is a convention for storing requirements as structured files in your repository. A “change” — a unit of work, roughly analogous to a feature or fix — lives in openspec/changes/<slug>/ as a set of markdown and YAML files.
The advantage over writing issues directly in GitHub is that specs live in the same place as the code, go through the same review process, and can be as rich and detailed as you need without hitting the limitations of issue tracker text fields.
The disadvantage is that not everyone on a team works in the repo. Stakeholders, designers, project managers — they work in the issue tracker. If your specs never show up there, they might as well not exist for a significant portion of the people who need to know what’s being built.
What specsync does
specsync is a CLI tool that takes your OpenSpec changes and renders them into GitHub issues. Run it and each change becomes an issue. Run it again and it updates the issues without creating duplicates — the sync is idempotent.
It also works the other direction: specsync pull -issue 42 reads an existing GitHub issue and scaffolds a local OpenSpec change from it. Spec-first and issue-first are both supported.
The binary is self-contained Go standard library — no runtime dependencies, no language-specific install, runs in any project.
No double-entry
The key word in the description is “idempotent.” Running specsync twice should produce the same result as running it once. This means you can run it in CI on every spec change without worrying about duplicate issues or stale data.
It also means there’s only one place to write intent: the spec file. The issue is a rendered view of that spec. You don’t maintain both — you maintain the spec and let specsync handle the rest.
Dogfooding
The specsync GitHub repo manages its own backlog with specsync. Every open issue was generated from a change in openspec/changes/. The issue body contains the rendered spec, including the task checklist. When a task is completed, the spec is updated and specsync re-renders the issue.
This serves two purposes: it proves the tool works on a real project, and it provides a working example of the CI workflow that anyone can copy.
Install
npm i -g @androidand/specsync
# or
go install github.com/androidand/specsync/cmd/specsync@latest
The project page has the full command reference, workflow examples, and instructions for setting up the GitHub Actions workflow that keeps everything in sync automatically.
Is spec-driven development for you?
Spec-driven development is not for every project. For a quick personal experiment, writing specs before code adds overhead without much benefit. For a team project where requirements need to be reviewed, referenced, and tracked over time, it’s worth the investment.
specsync is specifically useful when you’ve already bought into spec-first work and want a way to bridge the gap with the rest of your team’s tooling. It doesn’t impose a new workflow — it just removes one manual step from the workflow you already have.