Skip to main content
pinbox link turns a pin into a GitHub issue and keeps the two in sync from then on. Comments flow both directions. Closing either side closes the other. Use it when a pin needs to leave the loop — it is not a bug someone will fix in this session, and it belongs on the backlog where the rest of the team can see it.

Requirements

Pinbox has no GitHub dependency, no OAuth app, and no token of its own. It shells out to your gh:
If those work, pinbox works. Your credentials, your GitHub host, your enterprise config — all of it is gh’s, not ours.
gh runs with your project directory as its working directory, so the issue lands in whatever repository gh resolves there. Check with gh repo view if you are unsure. pinbox doctor reports the state:
All three say ok, and that is deliberate: the gh check is informational. It gates pinbox link and nothing else, so a missing gh never fails a doctor run. Read the detail, not the prefix.
github is the default connector, so pinbox link pin_a1b2c3d4e5 github is the same command. With --json you get the full updated pin back, links included:
ref is the issue number. Links do not show up in the human pinbox show output — read them from pinbox show <id> --json.
Running pinbox link twice on the same pin creates a second issue. Nothing deduplicates for you — the conflict guard only fires on an identical connector and ref. Link a pin once.

What lands on GitHub

The issue title is the pin’s first line, truncated to 72 characters. The body is the pin rendered as markdown, with a trailer identifying it:
Mirrored comments carry a trailer too — — pinbox <message-id>. Those trailers are how pinbox recognizes its own writing and refuses to read it back in, so don’t strip them.

Two-way mirroring

Once a pin is linked, the pin thread and the issue conversation are the same conversation.

Pin → issue

Every new thread message posts as an issue comment. That includes your pinbox reply and anything the agent writes.

Issue → pin

Every new issue comment appears in the pin thread with the role mirror and an origin of github:<username>.
So a teammate who never opens your app can answer a pin from the GitHub UI, and the agent working the pin sees it in the thread:
Echo is impossible by construction, not by heuristics: a message tagged with a connector’s origin is never mirrored back to that connector, and pinbox skips its own trailer-marked comments on the remote side too. The one interesting case is cross-connector — a comment that arrived from one tracker does flow out to a different one.

Status sync

Status moves both ways, and the rules are symmetric: A status change caused by the other side is never bounced back — closing an issue resolves the pin, and that resolution does not then re-close the issue.

When sync happens

Mirroring reconciles on a poll, not a webhook. Nothing needs to be exposed to the internet.
  • Every 60 seconds while the pin is open.
  • Every 10 minutes once it is resolved.
  • Once at hub start, so a link that went stale while nothing was running catches up immediately.
The hub runs on demand and exits when idle (30 minutes by default). Any pinbox command starts it again, and boot reconciliation is the first thing it does — so if you want to force a sync right now, run any pinbox command. Each reconcile flushes what pinbox owes the issue, in timestamp order, behind a resumable cursor. If the network drops halfway through, the cursor advances only over comments that actually landed — a retry resumes rather than reposting. You will not get duplicate comments on your issue.

Errors

E_CONNECTOR exits with code 10. Whether pinbox can reach GitHub is decided at hub start: if gh is on PATH at that moment, the connector is available for the life of that hub. If you install gh while a hub is already running, let it idle out (or stop it) so the next one picks gh up. Per-pin sync failures never take down the run. A failing link logs to stderr and stays due, so the next poll retries it.

Other trackers

link takes a connector name because GitHub is not the only one. The connector interface is small — create an item, post a comment, read remote state, set remote status — and the anti-echo and status rules live in pinbox core rather than in each connector, so a new one inherits them. A Slack connector ships alongside GitHub and turns on when both SLACK_BOT_TOKEN and SLACK_CHANNEL are set in the hub’s environment. Asking for a connector that is not available answers with E_CONNECTOR and a pointer to pinbox doctor, which lists what this hub can actually reach.