GitHub import

Point virta at a repo and it pulls in what it can: the project's description, homepage, package name and version (from package.json), and every issue as a task — title, body, labels as tags, open or closed, attributed to the GitHub author and dated when it was opened. That is how a real repo is onboarded, by UI or by the import verb.

Every event an import writes has a deterministic id (gh:owner/repo#12:created), and the sync log is idempotent by id, so importing again — to pick up new issues, or after a failed run — cannot duplicate anything. Once a repo is imported, virta is the source of truth for its tasks; GitHub issues become a place virta renders to.

Writing back (pushToGitHub, virta project push): an issue's reporter waits on GitHub, so a task that came from GitHub carries its outcome back — closed in virta, its issue is closed with the close reason as a comment (a task that ended obsolete or rejected closes it as not planned); reopened, it is reopened. Only imported tasks (gh: ids) are touched; an internal task never mirrors out. It reconciles against the issues' live state, so running it again changes nothing, and a dry run prints exactly what it would post.

The import uses GitHub's public API without a token (60 requests an hour per address); pass one for private repos or bigger backlogs.