GitHub Commit-Sync Guide
Drive tasks from commit messages — create, add subtasks, and close, all without touching GitHub Issues.
What it does
A project can bind one or more GitHub repos. A background poller reads new commits on every branch of each bound repo — not just the default branch — and parses commit messages for a task-command tag.
[Create-...] etc.) is the signal that it should be. This means work shows up in WorkX while it's still happening on a feature branch, not only once it's merged.Commit Message Patterns
Case-insensitive. taskKey is 2-40 alphanumeric characters (no hyphens) — reuse it across commits to keep referring to the same task.
Create — new task + first subtask
[Create-t8] Task Name - Subtask Name
[Create-t8-reqId] Task Name - Subtask Name (optional Requirement link)
[Create-t8] Task Name - Subtask Name | start=2026-08-10 end=2026-08-20 mh=5 pri=high labels=frontend,urgentThe - between Task Name and Subtask Name is required — a commit with no separator is silently ignored (no task, no error). The trailing | start= end= mh= pri= labels= segment is optional and sets startAt/endAt/estimatedManHour/priority/labels on creation. pri= accepts low|medium|high|urgent; labels= takes a comma-separated list. A malformed field (bad date, non-numeric mh, unrecognized pri value or key) is dropped individually — it never fails the task/subtask creation.
mh= is estimated from the commit's diff size (a rough starting number, meant to be corrected by hand); a missing pri= is guessed from keywords in the task/subtask name (e.g. “hotfix”/“urgent” → URGENT, “fix” → HIGH, “chore”/“docs” → LOW); a missing start= defaults to this commit's own timestamp. Either explicit field always overrides the guess. There's no way to guess end= up front — but if it's left out, it's filled in automatically once the task actually closes (the closing commit's timestamp), rather than staying empty forever. Separately, if the commit author resolves to a real user via an OAuth-verified GitHub username, the new task is auto-assigned to them with a notification — an unverified/self-declared username or a matching email is never auto-assigned (too easy to spoof), but it's always visible as a linkable suggestion in the GitHub tab, and picked up automatically on a later sync once the identity becomes OAuth-verified.Add — append a finished subtask
[Add-t8] Subtask NameAdds a subtask to an existing task, created already DONE — this pattern means “log work that's already finished,” not “add a TODO.”
Close — mark a subtask done
[Close-t8] Subtask NameMatches an existing subtask under that task by title (case-insensitive) and marks it DONE — creates it pre-closed if no subtask with that title exists yet. Once every subtask under the task is DONE, the task itself cascades to DONE automatically.
Add/Close referencing a taskKey with no matching task are silently skipped (logged as a worker warning, nothing surfaces in the UI). Double-check the Create commit actually landed first if a follow-up seems to have done nothing. And a repo that was never bound to a project is never polled at all — no binding means no automatic task creation, ever, by construction.[Create-...]/[Add-...]/[Close-...]) but fails to parse — a bad taskKey, a missing - separator — shows up as a near-miss commit in the GitHub tab, so a typo doesn't just vanish with no trace. An ordinary commit that was never trying to tag anything is unaffected. One sync run also caps how many new tasks a single push can create (default 50) — a bulk history import doesn't flood the project all at once, it just picks up the rest on the next tick.Manual Task Creation with a Commit Key
A task created by hand (not from a commit) can also be given a taskKey, via the “Task Key for GitHub commits” field on the New Task form — same 2-40 alphanumeric format, validated and lowercased the same way.
This makes it addressable by future [Add-key]/[Close-key] commits the same way a commit-created task already is. Leave it blank if the task never needs to be touched from a commit — it's entirely optional.
Setup (Org Owner only)
Open the GitHub tab
Go to a project → GitHub tab → Bind Repo.
Enter repo and token
Repo in owner/repo form. Personal Access Token needs Contents: Read-only (fine-grained, scoped to just that repo) or the classic repo scope for private repos.
Save
The token is validated against the GitHub API immediately — a bad token or inaccessible repo fails fast instead of silently creating a dead binding. It's encrypted at rest and never shown again after this point.
infra.github.manage) can bind/rebind/delete a repo, change its sync interval, or trigger a manual sync. Writing correctly-tagged commits doesn't require this permission — every project member can see this guide and the commit patterns above.Optional: GitHub OAuth Account Linking
A user's githubUsername (shown in commit attribution) can be set two ways:
- Typed free-text in Profile — unverified, display-only.
- “Connect GitHub” button in Profile — a real OAuth flow that marks it verified.
Both are optional and independent of repo binding — this is about who a commit's author resolves to, not which repos sync.