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
| File | Purpose |
|---|---|
.stax/sync.json | GitHub owner/repo, webhook secret, sync toggles, and deployment-log config. |
.stax/issues.json | Local issue cache used by the dashboard. |
.stax/discussions.json | Optional discussions cache. |
.stax/wiki.json | Optional wiki cache. |
.stax/releases.json | Optional releases cache. |
.stax/sync-log.jsonl | Append-only sync audit trail. |
.stax/deployments.jsonl | Append-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/githubcurl http://localhost:4800/api/sync/issuescurl 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
| Endpoint | Purpose |
|---|---|
GET /api/sync/config | Read normalized sync and deployment-log config. |
PUT /api/sync/config | Persist sync and deployment-log config. |
POST /api/sync/github | Run a pull sync for enabled GitHub entities. |
POST /api/sync/pr | Push a local stacked diff to GitHub as a PR branch. |
POST /api/sync/inbox | Receive signed GitHub webhook events. |
GET /api/sync/issues | Read local issue cache. |
GET /api/sync/audit | Read sync audit log. |
GET /api/deployments | Read 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
ghCLI, so the local operator must be authenticated.