Skip to content

Pull a GitHub issue into a local OpenSpec change #3

Description

@androidand

Pull a GitHub issue into a local OpenSpec change

Why

specsync only flows one way today: an OpenSpec change becomes an issue. But work
often starts on the tracker side — a human or an orchestrator files an issue
first, sometimes nearly empty, then wants to plan it as a spec. Without a way to
seed a local change from an existing issue, that planning happens off-spec and
the issue↔change link is invented by hand.

This is the missing reverse direction, and it is the first capability needed to
adopt specsync in a real multi-repo workflow: turn an existing issue into the
starting point of a spec.

What Changes

  • Add an issue-first pull: given a provider issue id, specsync materializes a
    local openspec/changes/<slug>/ from that issue (proposal.md from the body,
    tasks.md from a ## Tasks checklist when present).
  • Add an optional, type-asserted provider capability IssueReader so the
    core can read an existing item without bloating the minimal WorkProvider
    contract. Implement it for the GitHub provider via gh issue view.
  • Establish the round-trip link on pull: derive (or reuse) the change slug, strip
    the identity marker out of the proposal body, and cache the ref so a later
    push updates the same issue instead of creating a duplicate.
  • Add a pull subcommand to the CLI with -dry-run parity.

This change keeps the engine provider-agnostic and the GitHub specifics behind
the provider — the interface work that later admits other trackers, while we
deliberately ship GitHub only now.

Out of scope

  • bidirectional conflict resolution (a later change)
  • branch-based link resolution (the spec-issue-linker change)
  • epic and sub-issue projection
  • non-GitHub providers — this slice is deliberately GitHub-only

Capabilities

New Capabilities

  • issue-pull — materialize a local OpenSpec change from an existing tracker issue.

Modified Capabilities

  • work-provider — gains the optional IssueReader read capability.

Impact

  • New code: pull.go, IssueReader on provider.go, Get on the GitHub
    provider, a pull subcommand in cmd/specsync.
  • No change to the existing push path; Sync and its tests are untouched.
  • Enables the first real downstream use: seeding a portal onboarding spec from an
    existing GitHub issue.

Tasks

Tasks: Pull a GitHub issue into a local OpenSpec change

1. Provider read capability

  • 1.1 Define FetchedItem and the optional IssueReader interface in provider.go
  • 1.2 Implement Get on GitHubProvider via gh issue view --json (title, body, state, url, labels)

2. Pull engine

  • 2.1 Add Pull/PullOptions in pull.go, requiring a provider that implements IssueReader
  • 2.2 Resolve the slug: explicit flag, else existing body marker, else slugify the title
  • 2.3 Split the issue body: strip the marker, separate the ## Tasks section into tasks.md
  • 2.4 Write openspec/changes/<slug>/{proposal.md,tasks.md}, ensuring proposal has an H1 title
  • 2.5 Cache the ref so a subsequent push updates the same issue (no duplicate)

3. CLI

  • 3.1 Add a pull subcommand: specsync pull -issue <n> [-slug <s>] [-dry-run]
  • 3.2 Keep default (no subcommand) behaviour as today's push/sync

4. Tests

  • 4.1 Pull creates a well-formed change from a faked issue (body + tasks split)
  • 4.2 Pull on an issue with no ## Tasks writes proposal only
  • 4.3 Round-trip: pulled change pushes back to the same issue id (cache set)
  • 4.4 Dry-run pull writes nothing to disk

5. Docs

  • 5.1 Document the issue-first pull flow in the README

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions