Last updated 2026-05-07

GitHub Sync & Deployment Ledger

Stax keeps a local copy of GitHub collaboration state for the dashboard and can mirror production deployment records to a GitHub issue. The local copy lives in .stax/; GitHub remains the remote system of record for PRs, issues, comments, releases, and review threads.

Local state files

FilePurpose
.stax/sync.jsonGitHub owner/repo, webhook secret, sync toggles, and deployment-log config.
.stax/issues.jsonLocal issue cache used by the dashboard.
.stax/discussions.jsonOptional discussions cache.
.stax/wiki.jsonOptional wiki cache.
.stax/releases.jsonOptional releases cache.
.stax/sync-log.jsonlAppend-only sync audit trail.
.stax/deployments.jsonlAppend-only deployment ledger, one JSON record per tracked deployment run.

Configure in the dashboard

Open stax dashboard, go to /issues, and use the sync configuration dialog. The UI can enable bidirectional GitHub issue sync, set the owner/repo, configure tracked deployment environments, and choose the GitHub issue number that receives deployment comments.

If no issue number is set, Stax still writes .stax/deployments.jsonl. Mirroring to GitHub is opt-in because it requires a reachable GitHub CLI session and an issue chosen by the team.

Webhook forwarding

During local development, the runner is not publicly reachable. Use the GitHub CLI webhook forwarder to tunnel signed webhook events to the runner.

export STAX_GH_WEBHOOK_SECRET="change-me"
stax runner start
gh webhook forward \
--events=issues,issue_comment,pull_request,pull_request_review,pull_request_review_comment \
--url="http://localhost:4800/api/sync/inbox" \
--secret="$STAX_GH_WEBHOOK_SECRET"

The runner validates x-hub-signature-256 with the configured HMAC secret, ignores echo payloads with x-stax-sync-id, and keeps short-term replay protection for GitHub delivery IDs.

Manual sync

curl -X POST http://localhost:4800/api/sync/github
curl http://localhost:4800/api/sync/issues
curl http://localhost:4800/api/sync/audit

Manual sync pulls issues, discussions, wiki pages, and releases according to the toggles in .stax/sync.json. The dashboard uses the same endpoints for refresh actions.

Deployment ledger

When deployment logging is enabled, completed workflow runs are inspected for jobs with a tracked environment: value. By default Stax tracks production and prod. Matching runs are appended to .stax/deployments.jsonl.

{
"id": "a deployment record uuid",
"recordedAt": "2026-05-06T12:00:00.000Z",
"runId": "runner-run-id",
"workflow": "deploy",
"status": "completed",
"conclusion": "success",
"environments": ["production"],
"ref": "refs/heads/main",
"sha": "abc123...",
"jobs": [
{ "id": "deploy", "name": "Deploy", "environment": "production", "conclusion": "success" }
]
}

With GitHub mirroring enabled and an issue number configured, Stax also posts a structured comment containing workflow name, status, environment, ref, commit link, duration, run ID, deployment record ID, and job summary. The local record stores the GitHub comment URL when the mirror succeeds and stores the error if mirroring fails.

API surface

EndpointPurpose
GET /api/sync/configRead normalized sync and deployment-log config.
PUT /api/sync/configPersist sync and deployment-log config.
POST /api/sync/githubRun a pull sync for enabled GitHub entities.
POST /api/sync/prPush a local stacked diff to GitHub as a PR branch.
POST /api/sync/inboxReceive signed GitHub webhook events.
GET /api/sync/issuesRead local issue cache.
GET /api/sync/auditRead sync audit log.
GET /api/deploymentsRead local deployment records, newest first.

Current limits

  • GitHub Environments protection rules are not enforced locally.
  • The ledger records Stax runner executions; it does not import historical GitHub-hosted deployments.
  • GitHub issue mirroring uses the gh CLI, so the local operator must be authenticated.