Skip to content

Latest commit

 

History

History
247 lines (226 loc) · 61.4 KB

SPEC.md

File metadata and controls

247 lines (226 loc) · 61.4 KB

GitHub Sync plugin specification

GitHub Sync is a Paperclip plugin for registering one or more GitHub repositories and synchronizing their open issues into Paperclip projects.

Repository registration

The plugin MUST provide a settings page inside Paperclip where an operator can configure:

  • a GitHub token stored as a company-scoped Paperclip secret reference
  • an optional external config file at ${PAPERCLIP_HOME:-~/.paperclip}/plugins/github-sync/config.json for worker-only global values such as a raw githubToken
  • Paperclip board access, which is optional but configurable on deploymentMode: "local_trusted" deployments and required when the Paperclip deployment reports deploymentMode: "authenticated"
  • one or more GitHub repository mappings
  • company-scoped advanced defaults for imported issues: default assignee, default Paperclip status, executor/reviewer/approver handoff assignees for sync-driven status transitions, and ignored GitHub issue authors, where a saved username such as renovate also matches GitHub bot logins such as renovate[bot]
  • the frequency for automatic scheduled sync runs for that company
  • a Paperclip project name per mapping where synchronized issues should be created, including existing Paperclip projects that are already bound to a GitHub repository workspace

The settings page MUST allow saving mappings and triggering a manual sync.

  • When the settings page is opened with a Paperclip company context, it MUST only display and save repository mappings for that company, and saving one company’s mappings MUST preserve mappings that belong to other companies.
  • When the settings page is opened with a Paperclip company context, it MUST only display and save advanced issue defaults for that company, and saving one company’s defaults MUST preserve defaults that belong to other companies.
  • The settings page SHOULD clearly label company-scoped setup and defaults, including sync cadence, for the active company.
  • When a company context is present, the settings page SHOULD show the active company name prominently using a human-friendly label instead of a raw identifier.
  • When a company already has Paperclip projects bound to GitHub repository workspaces, the settings page SHOULD surface those projects so an operator can enable sync without recreating the project.
  • The settings page MUST render the Paperclip board-access connect controls when the current Paperclip deployment reports deploymentMode: "authenticated" or deploymentMode: "local_trusted", while only treating board access as required for sync when the deployment reports deploymentMode: "authenticated".
  • When the settings page successfully validates a saved GitHub token, it SHOULD persist the validated GitHub login as non-secret display metadata so later visits can continue showing Authenticated as ... instead of falling back to a generic ready state.
  • When the settings page successfully connects Paperclip board access for a company, it SHOULD persist a company-scoped non-secret identity label so later visits can continue showing Connected as ... instead of falling back to a generic connected state.
  • When the active company has a saved Paperclip board-access user id, every advanced-settings assignee dropdown MUST include a Me option that maps to that connected board user alongside the available agents.
  • Execution-policy fallback dropdown copy SHOULD use operator-facing language such as Automatic routing and explain that Paperclip execution-policy participants and returnAssignee win before company-level reviewer, approver, or executor fallbacks.
  • The plugin SHOULD also expose manual sync entry points from Paperclip toolbar surfaces when the SDK supports them.
  • When a manual sync will outlive a quick action response, the worker MUST persist a running sync state immediately and complete the sync asynchronously.
  • Once a sync is running, the settings page, dashboard widget, and toolbar sync entry points MUST provide a way to request cancellation, and the worker MUST stop cooperatively after the current repository or issue step finishes.
  • If a worker restart or similar interruption leaves a persisted sync state in running without a live in-memory sync behind it, the next worker-visible read or control path MUST reconcile that orphaned run into an interrupted error or cancelled result instead of leaving the UI stuck in running or silently restarting the abandoned run.
  • The settings page, dashboard widget, and sync toolbar surfaces SHOULD detect authenticated deployments from /api/health and MUST require connected Paperclip board access before enabling sync for the affected company.

Secret handling

  • The raw GitHub token MUST NOT be persisted in plugin state.
  • Saving a token from the settings UI MUST create or reuse a company secret through the Paperclip host API.
  • The plugin MUST persist only the resulting secret UUID, keyed by company, in plugin state and MUST mirror it into that company's plugin config as the shared { "type": "secret_ref", "secretId": "<uuid>" } binding, because Paperclip 2026.831 binds and resolves plugin secret refs only from that shape and only for the company that owns the config row.
  • The worker MUST resolve that secret at runtime via ctx.secrets.resolve({ type: "secret_ref", secretId }, { companyId, configPath }), MUST accept both the binding object and the pre-2026.831 bare UUID string when reading plugin config or plugin state, and MUST report a config-repair signal to the settings UI when plugin config still holds a bare UUID so the UI re-mirrors it as a binding.
  • UI-side plugin config writes MUST recover from the known plugin-secret-reference-disabled failure by retrying without plugin secret-ref maps, so saving non-secret settings cannot be blocked by stale secret-ref config.
  • If a Paperclip host cannot resolve a plugin secret ref for the worker (the pre-2026.831 plugin-secret-reference-disabled failure, a 2026.831 binding_missing/invalid-reference failure for a ref that is not bound as a binding, or a denied company scope), the settings UI MAY ask the worker to persist the validated raw token in a worker-local company-scoped fallback map at ${PAPERCLIP_HOME:-~/.paperclip}/plugins/github-sync/config.json so production sync can continue without writing the raw token to plugin state or plugin config. Host-resolved secret refs remain the primary path.
  • The plugin MAY persist lightweight non-secret display metadata such as the validated GitHub login alongside the saved GitHub token secret ref so hosted UI can keep connected-state copy consistent across refreshes without resolving the secret.
  • The settings UI MUST NOT propagate the saved GitHub token into agent adapterConfig.env; authenticated agents should use Paperclip's plugin tool dispatcher for GitHub Sync tools instead of receiving GITHUB_TOKEN from this plugin.
  • The settings UI MAY offer an explicitly opt-in, default-off control that additionally stores the same validated GitHub token as a company secret named exactly GITHUB_TOKEN, which is the name Paperclip's own GitHub features probe for managed-checkout git credentials, merged-PR confirmation, workspace reaping, and external-object liveness. When enabled it MUST match the existing secret name exactly because the host compares secret names byte for byte, MUST create that secret or rotate the existing one in place rather than creating a second copy, MUST refuse to rotate a secret the host reports as non-active, MUST NOT change the plugin's own secret reference, and a failure to write it MUST NOT fail the GitHub token save.
  • If ${PAPERCLIP_HOME:-~/.paperclip}/plugins/github-sync/config.json exists and contains either a string githubToken or a githubTokensByCompanyId map, the worker MUST treat those values as worker-only fallback sources for the GitHub token without persisting or returning those raw tokens.
  • The raw Paperclip board API token MUST NOT be persisted in plugin state.
  • Connecting Paperclip board access from the settings UI MUST create or reuse a company secret through the Paperclip host API and MUST persist only the resulting secret UUID, keyed by company in plugin state and mirrored into plugin instance config when the host allows plugin secret refs there.
  • If the host cannot resolve saved board-access secret refs for plugin workers, the settings UI MAY pass the approved raw board token to a worker action that persists a company-scoped worker-local fallback in ${PAPERCLIP_HOME:-~/.paperclip}/plugins/github-sync/config.json so direct Paperclip REST sync calls can continue without storing the raw board token in plugin state or plugin config.
  • The plugin MAY persist lightweight company-scoped non-secret display metadata such as the connected board identity label alongside the saved board token secret ref so hosted UI can keep connected-state copy consistent across refreshes without resolving the secret.
  • The worker MUST resolve the saved Paperclip board token secret at runtime via ctx.secrets.resolve(...) before making direct Paperclip REST calls for that company, falling back to the company-scoped worker-local board token only when host secret-ref resolution is unavailable.

Synchronization behavior

The plugin MUST persist repository mappings, company-scoped advanced issue defaults, and sync state in plugin state.

  • The worker MUST expose at least one data endpoint for reading the current settings and sync status.
  • The worker MUST expose action endpoints for saving mappings and triggering a manual sync.
  • The worker MUST expose a company-scoped dashboard KPI read model that returns backlog history, GitHub issue-closure activity, and Paperclip-attributed pull request activity for the dashboard widget.
  • The worker SHOULD expose project-scoped pull request read models and actions for mapped repositories, including a lightweight queue read, a lightweight open-count read for sidebar badges, an on-demand detail read, and row-level actions for linking a Paperclip issue, updating a behind-but-clean branch, posting Copilot requests, merging, closing, and commenting.
  • The worker SHOULD keep the default pull request queue read lightweight, use a lighter repo-wide metrics read for the summary cards, keep a separate cached full-summary path for filtered views, and invalidate those caches after pull request mutations.
  • When resolving a Paperclip issue for a pull request, the worker SHOULD first match GitHub issues referenced in closingIssuesReferences to imported Paperclip issues and only fall back to pull-request-created issue links when no closing-issue match exists.
  • The sync.runNow action SHOULD support a prompt-running-state response for callers that pass waitForCompletion: false, but built-in UI and scheduled-job callers MUST wait for completion so nested Paperclip host service calls keep their invocation scope for the full sync.
  • A manual sync requested from a company-scoped settings or dashboard view MUST only sync repository mappings for that company.
  • The worker SHOULD support targeted manual sync requests for a specific mapped Paperclip project, imported Paperclip issue, or Paperclip issue linked directly to a GitHub issue or pull request.
  • The plugin MUST declare a scheduled job that ticks every minute and only performs a scheduled sync when the saved frequency is due.
  • The plugin MUST expose agent tools for the GitHub issue and pull request workflow around synced work, including repository-item search, issue reads and updates with GitHub-native completed, not_planned, duplicate, and reopened state reasons, assign_to_current_user for assigning issues to the GitHub user authenticated by the saved token, issue comment reads and writes, pull request creation and updates, pull request asset upload, pull request file and CI inspection, review-thread reads and replies, review-thread resolution changes, request_pull_request_reviewers reviewer requests, organization-level GitHub Project search/listing, associating pull requests with organization-level GitHub Projects, and link_github_item for linking a Paperclip issue to a GitHub issue or pull request in mapped or third-party repositories.
  • Agent tools that send non-empty freeform GitHub body content, such as issue bodies, pull request descriptions, comments, or review-thread replies, MUST append a GitHub-flavored Markdown footer that uses a horizontal rule plus a compact heading to disclose that a Paperclip AI agent created the message. When the caller provides an llmModel, that footer MUST also include which LLM was used.
  • The plugin MUST expose an agent-authenticated native plugin JSON API route for recording Paperclip-attributed pull request metric events, and create_pull_request MUST automatically record a pull-request-created metric event when it succeeds.
  • create_pull_request MUST be the single agent-facing operation for branch publication and pull-request creation. It MUST require a Paperclip issue id, plain local head branch name, exact full local branch-tip commit SHA, base branch, and PR title.
  • create_pull_request MUST assert issue checkout ownership and resolve the issue's trusted execution workspace plus company-scoped GitHub secret inside the plugin worker. It MUST NOT use the project primary workspace, require or return an agent-visible GitHub token, or expose a separate agent-facing branch-push tool.
  • Before creating the PR, create_pull_request MUST verify that the issue and execution workspace belong to the calling run company and project; the issue is checked out by the calling agent/run; any requested local checkout path resolves within the trusted execution workspace; the requested branch is checked out in that selected Git checkout; both checkout HEAD and the local branch tip equal the supplied commit SHA; the head differs from the base; and the commit descends from the fetched remote base. An explicit target repository MAY be outside Paperclip repository mappings and MAY differ from the checkout's configured remotes; when omitted, the tool MUST infer the repository only from an unambiguous project mapping. It MUST publish only the exact commit to the exact head branch without force, verify the remote SHA, and only then call GitHub's PR API. GitHub token permissions are the authority for whether publication and PR creation are allowed.
  • Branch publication MUST use a sanitized Git execution context that does not execute repository hooks or honor agent-controlled credential helpers, remotes, proxies, or arbitrary refspecs. Errors and logs MUST redact the resolved token.
  • After successful PR creation, create_pull_request MUST persist a pull-request link entity for the supplied Paperclip issue so scheduled/manual sync can reconcile that issue from PR status even when the PR does not close a synced GitHub issue.
  • create_pull_request MAY accept optional labels, userReviewers, and teamReviewers. The worker MUST apply them only after the pull request exists, MUST NOT undo or fail the creation when those follow-up calls fail, and MUST report their outcome in the result as labels, requestedReviewers, requestedTeams, or warnings.
  • After persisting the pull-request link, create_pull_request MUST append the new pull request to the issue's issue-link record (linkedPullRequestNumbers and linkedPullRequests) so issue detail surfaces show it before the next sync. Issue-link record writes from tools and from sync MUST be serialized per company and Paperclip issue so concurrent writers cannot drop a link.
  • update_pull_request MAY accept a replacement labels set. When provided, the pull request MUST end with exactly those labels; an empty array clears them.
  • get_issue MUST return the GitHub issue author (login, plus url and association when available) so agents can route reviewer requests to the reporter.
  • get_issue MUST also return participants (the author plus each distinct comment author with role, repository association, and bot flag) and reviewerCandidates (the non-bot participants whose association is owner, member, or collaborator) so agents can request the reporter and the repository members who commented on the issue as pull request reviewers. When comments cannot be listed, the tool MUST still return the author-only participants and a participantsWarning.
  • Every pull-request link MAY store an optional company-scoped followThroughAssigneeAgentId. create_pull_request, link_github_item, the authenticated pull-request metric route, and hosted PR-link actions MUST accept the field explicitly where they create or update a PR link and MUST use the same validation/persistence logic. An omitted property MUST preserve the current owner, an explicit null MUST clear it, and a successful response SHOULD expose the persisted owner plus followThroughAssigneeUpdatedAt when present.
  • Before storing a non-null follow-through owner, the worker MUST resolve the agent through the authoritative host agent service and verify that it exists in the authenticated company. Missing or cross-company ids MUST fail closed before the link mutation. Owner changes through audited agent tools MUST remain represented in the existing issue-interaction intent/result ledger, and the durable link timestamp MUST make the current assignment change observable.
  • The follow-through owner MUST survive ordinary PR title/state refreshes, worker process restarts, state reload, and execution-state settlement or cleanup. Pull-request link records written before this field existed MUST continue to normalize and sync without migration; their assignment behavior MUST remain the existing configured fallback behavior.
  • Pull-request agent tools invoked with paperclipIssueId MUST resolve those direct pull-request link entities as well as pull requests discovered through a linked GitHub issue. When multiple direct links have the same pull-request number in different repositories, the caller MUST supply a matching repository; the worker MUST reject ambiguous or unlinked selections.
  • create_pull_request MUST be retry-safe across partial outcomes. If GitHub reports that a PR already exists after exact-SHA publication, the worker MAY reuse an open PR only when repository, head branch, base branch, and head SHA all match, then MUST reconcile the durable link and metric. It MUST NOT delete branches or close PRs as automatic compensation.
  • That API route MUST accept pull_request_created, MUST use the host-provided authenticated agent company as the metric company, MUST reject any payload companyId that disagrees with that company, and MUST deduplicate repeated events using a stable pull-request identity or an explicit event key.
  • When that API route receives a Paperclip issue id, it MUST verify the live pull request and persist the same pull-request link entity that create_pull_request writes, so PRs created through gh or another non-plugin client still feed future issue status sync.
  • That API route MUST rely on the Paperclip host's api.routes.register authentication and company access checks, so missing, invalid, expired, non-agent, or cross-company PAPERCLIP_API_KEY requests are rejected before worker dispatch.
  • The plugin MUST expose link_github_item as the agent-facing way to link a Paperclip issue to a GitHub issue or pull request. The tool MUST use the authenticated tool run company, MUST verify the live GitHub item, and MUST persist the same durable issue-link or pull-request-link entity that hosted manual link actions write.
  • The plugin MUST expose upload_pull_request_asset as the agent-facing way to upload pull request assets. The tool MUST accept arbitrary base64 content or data URLs, including images and PDFs, MUST enforce the asset size limit, MUST write the asset to a non-merge artifact branch such as paperclip-artifacts-pr-<number>, and MUST return an immutable raw GitHub URL plus Markdown suitable for the PR description. Image assets SHOULD return image Markdown, while non-image assets SHOULD return standard Markdown links.
  • The sync flow MUST fetch open GitHub issues from every configured repository.
  • The sync flow MUST also include company-scoped GitHub issue and pull request link entities whose repositories are not covered by a configured mapping, and for those third-party repositories it MUST fetch only the linked GitHub issue or pull request instead of importing or scanning the entire repository.
  • Full company and global sync runs MUST persist a company backlog snapshot using the current open GitHub issue count for each fully planned company mapping.
  • When sync observes an already-imported GitHub issue move from open to closed, it MUST record a company-scoped closed-issues KPI event exactly once for that transition.
  • The sync flow MUST ignore GitHub issues whose author username matches a configured ignored username for that mapping company.
  • The sync flow MUST create one top-level Paperclip issue per imported GitHub issue when the target mapping has a resolved Paperclip project identifier.
  • When the Paperclip runtime exposes plugin issue creation, the sync flow SHOULD prefer ctx.issues.create(...) for imported issue creation and reserve direct Paperclip REST issue calls for repair or update paths so imported issues are not attributed to the connected board user.
  • Imported GitHub issues MUST be created with a GitHub Sync namespaced plugin origin and the canonical GitHub issue URL as originId.
  • Imported GitHub issues MUST be created in neutral backlog status without a configured assignee so issue creation itself does not activate work before durable recovery state exists. The namespaced origin and canonical originId MUST be written atomically with creation so a restart can recover the same issue without duplication.
  • When a Paperclip issue has a GitHub Sync GitHub-issue or pull-request originKind and a parseable GitHub URL in originId, issue-scoped GitHub detail reads MUST use that origin metadata as a durable fallback when plugin-owned link entities, import-registry entries, or hidden description markers are missing.
  • After a new or origin-recovered import has durable activation state, the sync flow MUST apply the configured default status and assignee. When activation requires an agent wake, its intent MUST be persisted before status or assignment mutation and retried with the same episode identity after interruption.
  • Imported Paperclip issues MUST keep the original GitHub issue title without adding a [GitHub] prefix.
  • Imported issue descriptions SHOULD contain the normalized GitHub body when present and MUST normalize the GitHub raw HTML constructs that Paperclip cannot render in multiline descriptions.
  • Imported issue descriptions MUST also retain a machine-readable hidden marker for the source GitHub issue URL so agents and repair paths can still recognize imported issues when plugin-owned entity or registry state is missing.
  • GitHub repository, issue, PR, label, and sync metadata SHOULD move into a dedicated issue detail surface instead of being prepended into the issue description.
  • Repeated sync runs MUST continue reconciling imported Paperclip issue descriptions against the latest GitHub issue body.
  • Direct Paperclip REST calls from manual setup or sync actions MUST use the current browser origin by default. When the GitHub Sync settings page's optional Worker Paperclip API URL field is filled, the settings UI MUST persist it into plugin config paperclipApiBaseUrl and the worker/action path MUST use that configured origin instead of browser origin.
  • The worker MUST treat the plugin-configured Paperclip API origin as the trusted source for direct authenticated Paperclip REST calls, and MUST reject ad hoc action inputs that point at a different origin.
  • The worker MUST NOT rely on a Paperclip process environment variable named PAPERCLIP_API_URL; release-target e2e verification uses an explicit Worker Paperclip API URL because plugin worker runtime environments do not guarantee that process variable.
  • Direct Paperclip REST fetch failures MUST preserve method, URL, primary error, nested cause message, and cause code in diagnostics when available so TLS and routing problems remain actionable.
  • Before a manual or scheduled sync touches any mapping whose company is missing board access, the worker MUST probe /api/health on the resolved Paperclip API origin and fail fast with configuration guidance when that deployment reports deploymentMode: "authenticated".
  • When a company has connected Paperclip board access, the worker MUST attach Authorization: Bearer <board-token> to direct Paperclip REST issue and label calls for that company, using the saved secret ref when resolvable and the company-scoped worker-local board-token fallback when plugin secret refs are disabled.
  • When the Paperclip runtime exposes existing issue labels for the target company, the sync flow MUST map GitHub labels onto matching Paperclip labels by name and SHOULD prefer an exact color match when multiple Paperclip labels share the same name.
  • When no matching Paperclip label exists and the local Paperclip label API is reachable, the sync flow MUST create the missing Paperclip label using the GitHub label color when available before attaching it to the imported issue.
  • When a local Paperclip REST call returns an unexpected non-JSON success payload, such as an authenticated HTML sign-in page, the worker MUST treat that response as unavailable, fall back to SDK-based issue mutation when possible, and surface an actionable sync error that points operators to Paperclip board access or the Worker Paperclip API URL setting when labels still cannot be reconciled.
  • Repeated sync runs MUST skip recreating issues that were already imported for the same mapping.
  • If the plugin-owned import registry is stale or missing, repeated sync runs MUST repair deduplication by reusing an existing imported Paperclip issue in the mapped project when its GitHub Sync origin metadata, durable GitHub link metadata, or, for legacy issues, description source link matches the canonical GitHub issue URL.
  • When a linked GitHub issue is transferred to another repository, sync MUST detect the canonical issue URL returned by GitHub. If the destination repository is mapped to a Paperclip project in the same company, sync MUST move the existing Paperclip issue to that project, update the active GitHub link metadata and import-registry row, and avoid creating a duplicate Paperclip issue. If the destination repository is not mapped, sync MUST unlink the Paperclip issue from GitHub and transition it to cancelled with an explanatory Paperclip comment.
  • The worker SHOULD persist pull request to Paperclip issue links in a plugin-owned entity so project-scoped queue and detail surfaces can reuse durable links without reparsing issue descriptions.
  • Repeated sync runs MUST continue reconciling imported Paperclip issue statuses against the latest GitHub state.
  • Repeated sync runs MUST also monitor pull requests that were linked to Paperclip issues through the project Pull Requests page, the create_pull_request agent tool, the link_github_item agent tool, the agent-authenticated metric API route, or the manual issue-page fallback when those pull requests do not close a synced GitHub issue, and MUST reconcile those Paperclip issue statuses from the pull request CI, merge, review decision, review-thread state, and terminal merge/closed state.
  • For Paperclip issues linked directly to pull requests, open linked PRs MUST continue to drive the active/review status from CI, mergeability, review decision, and review-thread state. When all directly linked PRs are terminal, any merged linked PR MUST map the Paperclip issue to done; only closed-unmerged linked PRs MUST map it to cancelled.
  • Direct pull-request sync MUST persist bounded per-PR top-level and review-comment watermarks. A newly observed comment from that pull request's author or a verified repository maintainer/admin MUST re-arm non-backlog work even when the effective PR fingerprint is unchanged; untrusted comments MUST advance the observation watermark without re-arming the issue.
  • Direct pull-request links MUST act as fallback status drivers only for Paperclip issues that are not also linked to a GitHub issue. When the same Paperclip issue is linked to a GitHub issue, the live GitHub issue snapshot and its closing pull-request references MUST own the status decision so stale direct pull-request links cannot terminalize still-open GitHub issue work.
  • Repeated sync runs MUST continue reconciling Paperclip issues linked directly to third-party GitHub issues from the live GitHub issue state, labels, description, linked pull requests, and trusted comment rules without requiring that GitHub repository to be mapped to a Paperclip project.
  • When the local Paperclip host API is available, sync-driven Paperclip status transitions SHOULD go through the same issue-update path Paperclip UI uses so timeline activity is recorded for agents and humans.
  • Repeated sync runs MUST continue reconciling imported Paperclip issue labels against the latest mapped GitHub labels, including removing labels that were removed on GitHub.
  • An open GitHub issue without a linked PR that was created by a repository maintainer/admin MUST map to Paperclip todo when it is first imported.
  • An open GitHub issue without a linked PR MUST otherwise map to the configured default Paperclip status when it is first imported, and that default MUST be backlog when the company has not chosen another status.
  • If a real Paperclip host creates a newly imported maintainer-authored issue in backlog before first-sync reconciliation promotes it to todo, that promotion MUST preserve the imported default assignee instead of applying the configured executor handoff assignee.
  • When a newly imported GitHub issue finishes sync in Paperclip todo and is assigned to an agent, the worker MUST best-effort enqueue an assignment wakeup for that assignee using the imported Paperclip issue as wake context, preferring ctx.issues.requestWakeup(...) and only falling back to the local Paperclip wakeup route when the SDK path is unavailable or rejected before dispatch.
  • When sync moves a Paperclip issue into in_review, the worker MUST prefer the current reviewer or approver from the issue execution policy and execution state when Paperclip exposes that participant. If a visible internal review or approval stage exists but Paperclip does not expose the participant yet, the worker MUST fall back to the configured reviewer or approver handoff assignee when one is saved. If no internal review or approval stage is visible and the transition is only waiting on a healthy linked pull request, the worker MUST leave the issue unassigned instead of waking an internal reviewer or approver. An execution state explicitly marked completed MUST be treated as historical terminal evidence even when completed-stage, final-decision, or return-assignee fields remain populated; when an open healthy PR restores such an issue from done to in_review, the worker MUST atomically clear the completed execution policy/state and the agent assignee and MUST NOT request an assignment wakeup.
  • When sync moves a Paperclip issue back into active execution (todo or in_progress), assignment precedence MUST be: an active issue execution-state returnAssignee; the actionable directly linked pull request's durable followThroughAssigneeAgentId; the configured executor handoff assignee; then the default imported assignee. A completed/settled execution state MUST NOT shadow the durable PR owner. If the stored owner no longer resolves to an agent in the company, sync MUST ignore it and continue through the configured fallbacks.
  • A tombstoned (unlinked) GitHub issue link record MUST NOT count as an existing import. Unlinking is how an operator detaches a Paperclip issue from a GitHub issue; the registry-repair lookup MUST honour it, so the next sync imports a fresh Paperclip issue instead of re-adopting the detached one.
  • Once sync has moved an issue out of blocked, it MUST NOT do so again until the externally observable state of the linked pull requests changes. The worker MUST persist a hash of that state (repository, number, head SHA, CI state, mergeability, merge state status, review decision, unresolved-review-thread flag) at the moment it leaves blocked, and MUST preserve blocked while the current hash equals it. blocked is a deliberate decision by an agent or a human; sync owns changes in GitHub, not steady state. An issue with no linked pull request has no external state and MUST never be held back by this rule.
  • A directly linked PR with red CI, an actionable unresolved review thread, a merge conflict or other action-required merge state, or trusted follow-up MUST assign and wake its selected durable owner when that owner wins the precedence above. A healthy external-maintainer wait MUST remain unassigned even when its link has an owner. The owner MUST remain on the link when execution state is cleared or settled.
  • Unassigning an issue for a maintainer wait means removing the agent assignee only. When the issue carries a human assignee, the worker MUST keep it: a person parked on an in_review issue is the reviewer the work is waiting on, not stale agent routing. The worker MUST write that preserved human assignee into the same patch it uses for the transition, so a settled maintainer wait is recognised as already applied and is not re-patched (or re-ledgered) on every sync pass.
  • Configured default, reviewer, approver, and executor handoff assignees MAY target either a Paperclip agent or the connected board user for that company.
  • When sync moves an assigned issue into an actionable agent-owned state because of a sync-driven status transition, the worker MUST best-effort enqueue an explicit assignment wakeup for that assignee using the imported Paperclip issue as wake context, preferring ctx.issues.requestWakeup(...) and only falling back to the local Paperclip wakeup route when the SDK path is unavailable or rejected before dispatch.
  • After successfully applying any GitHub-derived status, the worker MUST immediately persist a bounded fingerprint of the effective issue/PR condition before dispatching a required wake. The effective fingerprint MUST cover identity, head SHA, issue/PR closure outcome, and the highest-priority actionable check/review/merge condition, MUST cover directly PR-linked issues and terminal done/cancelled actions, and MUST NOT change for comment counts or transient raw UNKNOWN/aggregate jitter that leaves the effective action unchanged. An unchanged effective fingerprint MUST suppress repeated transitions, explanatory comments, and assignee wakes only when local Paperclip status, assignment, and execution metadata already match the desired state. Local drift under unchanged remote evidence MUST be corrected through a drift-specific journal attempt, including one required wake when the corrected state is actionable and agent-owned. Changed effective fingerprint evidence and trusted new issue, pull-request, or review-thread comments MUST bypass suppression. Failed status actions MUST NOT advance trusted-comment watermarks. A failed required wake MUST remain durably pending and retry without repeating the already successful status/comment mutation.
  • Every sync-driven transition MUST use a fixed-length semantic action identity that includes the Paperclip issue, target state, effective remote action, and trusted-comment watermarks. The worker MUST durably journal separate comment and issue-mutation intents/results, reuse completed phases on retry, keep the first intent timestamp stable, and fail closed when an intent has no trustworthy result. It MUST NOT repeat a transition comment or issue mutation merely because final result persistence or a later wake failed.
  • If an imported Paperclip issue is currently backlog and its linked GitHub issue is still open, the sync flow MUST preserve backlog; only a manual Paperclip transition may move it out of backlog.
  • If a Paperclip issue that came from an open GitHub issue without a linked PR is later moved out of backlog, the sync flow SHOULD preserve that Paperclip status until another open-issue GitHub rule applies.
  • If that Paperclip issue is currently done or cancelled while the linked GitHub issue is open with no linked PR, the sync flow MUST move it to todo instead of backlog so it re-enters the active queue.
  • An open GitHub issue with a linked PR that still has unfinished CI jobs MUST map to Paperclip in_progress, except when the Paperclip issue is already blocked and the only adverse PR signal is pending external merge requirements such as GitHub BLOCKED or UNSTABLE; in that case sync MUST preserve blocked instead of waking an executor.
  • An open GitHub issue with a linked PR that has red CI jobs, an action-required GitHub merge state such as CONFLICTING, DIRTY, BEHIND, BLOCKED, DRAFT, or UNSTABLE, or unresolved review threads MUST map to Paperclip todo, unless the worker can route the issue back to an executor through execution-policy or configured handoff data, in which case it MUST map to in_progress.
  • An open GitHub issue with a linked PR that has green CI, a review-ready GitHub merge state such as CLEAN or HAS_HOOKS, and all review threads resolved MUST map to Paperclip in_review; aggregate GitHub CHANGES_REQUESTED alone MUST NOT move that wait back to active execution without an actionable unresolved thread, failing or pending CI, action-required merge state, draft state, or trusted new comment.
  • An imported Paperclip issue that is currently blocked and has any non-terminal blockedBy issue MUST remain blocked during GitHub Sync even when the linked GitHub issue or PR otherwise looks review-ready.
  • An open GitHub issue with a linked PR in GitHub merge state UNKNOWN MUST NOT be treated as review-ready on first import or while the issue is already in active execution. When an imported Paperclip issue is already in_review, or is being reopened from done with a linked PR, transient UNKNOWN mergeability MUST preserve or restore in_review if CI is green, all review threads are resolved, and no trusted new comment, draft state, explicit action-required merge state, or unresolved first-class blocker applies.
  • Linked pull requests MAY live in a different GitHub repository than the linked issue, and the worker MUST evaluate CI, review-thread state, stored link metadata, and rendered GitHub deep links against each pull request's actual repository instead of assuming the issue repository.
  • A closed GitHub issue completed as finished work MUST map to Paperclip done.
  • A closed GitHub issue closed as not planned or duplicate MUST map to Paperclip cancelled.
  • When sync moves an imported Paperclip issue into done or cancelled, or sees an already-terminal imported issue whose GitHub source is still terminal, it MUST clear any pending Paperclip review or approval execution policy/state as part of that same reconciliation so the host does not reject the terminal status update or keep waking stale review participants.
  • A new GitHub comment on an open imported issue MUST move the corresponding Paperclip issue back into active work only when at least one newly added comment since the last sync was written either on the source GitHub issue, in a linked pull request's top-level comment stream, or in a linked pull request review thread by the original GitHub issue author or by a repository maintainer/admin that the worker can verify through the GitHub API; that active-work status MUST be in_progress when the worker can route the issue back to an executor through execution-policy or configured handoff data and todo otherwise.
  • A new GitHub comment from any other GitHub account MUST NOT move the corresponding Paperclip issue back into active work.
  • If that Paperclip issue is currently backlog, trusted GitHub comments MUST still leave it in backlog.
  • Whenever the sync flow changes a Paperclip issue status, it MUST add a Paperclip issue comment that explains the old status, the new status, and the GitHub condition that caused the transition.
  • The worker MUST append sanitized issue-scoped interaction events as paperclip-github-plugin.issue-interaction-event entities for sync status decisions (including no-ops and direct-PR-driven transitions) and issue-scoped mutating agent tool attempts. Before a mutation, it MUST persist a uniquely identified intent event; if that write fails, it MUST NOT execute the mutation. Concurrent identical mutation attempts MUST retain distinct logical attempt identities. It MUST persist a separate result event afterward, including a failed result for known mutation/comment/annotation failures. Intent/result persistence failures MUST return structured tool errors rather than rejecting the tool invocation; a result-write failure after a failed mutation MUST surface both failures. Only structured :intent events without a matching :result event MUST be reported as uncertain attempts rather than successful writes. Each entity MUST use a content-addressed externalId, keep the logical dedupe key in sanitized event data, preserve company/issue plus available agent/run attribution, and retain normalized remote identifiers resolved from authoritative Paperclip issue/PR links, derivable from repository/number, reference, or pullRequestUrl inputs, or returned by newly created GitHub items. It MUST NOT persist raw comment/body content, logs, credentials, headers, secret refs, or provider payloads. Persisted HTTP(S) URLs MUST have userinfo, query strings, and fragments removed. Concurrent identical writes MUST converge without overwriting different content; conflicting content under one logical dedupe key MUST make ledger coverage incomplete. A sync status decision that reaches the same no-op conclusion from unchanged state as an already-settled attempt in the same interaction family MUST reuse that attempt's identity and occurredAt so repeated passes converge on the stored events instead of appending a new intent/result pair each time; attempts that are still open, or that mutate, MUST take a new identity.
  • The plugin MUST expose get_issue_interaction_summary for authenticated agents. The tool MUST verify the Paperclip issue in the authenticated run company, accept an optional maximum 30-day UTC [from,to) range, return deterministic bounded counts/transitions/repeat-and-reversal signals with dimensioned plugin-ledger/Paperclip-core/external-GitHub coverage and limitations, and perform no historical backfill. Malformed rows, conflicting logical keys, or a bounded ledger-scan cutoff MUST make plugin-ledger coverage incomplete and be reported in integrity metadata.
  • When the SDK supports comment annotations, the plugin SHOULD render the referenced GitHub issue and PR links as a comment annotation attached to those sync-created comments.

Project binding behavior

  • Saving a mapping MUST create or reuse the target Paperclip project.
  • Saving a company-scoped mapping from the settings page MUST create or reuse the target Paperclip project in that same company.
  • When the settings page creates a new target Paperclip project, it MUST set executionWorkspacePolicy.enabled to true and executionWorkspacePolicy.defaultMode to "isolated_workspace" so the project opts into isolated issue checkouts and new issues default to isolated checkout.
  • Saving a mapping for a Paperclip project that is already bound to the GitHub repository MUST reuse that existing project instead of creating a duplicate workspace binding.
  • Saving a mapping MUST bind the GitHub repository URL to the Paperclip project workspace.
  • Once a project has been created and linked, its project name field SHOULD be treated as read-only in the settings UI.

Host integration requirements

  • The plugin MUST register successfully in Paperclip.
  • The plugin manifest MUST NOT declare a strict minimumHostVersion or minimumPaperclipVersion gate while current latest/development Paperclip hosts may report 0.0.0 during plugin upgrade. Required host surfaces MUST remain represented by manifest capabilities and guarded by worker fallbacks where possible, and the docs MUST still state the intended Paperclip 2026.831.1 support baseline.
  • Disposable e2e and manual host verification MUST pin the Paperclip CLI to 2026.831.1 by default, while retaining an explicit environment override for forward and backward compatibility checks.
  • The plugin MUST expose a dashboard widget contribution for sync readiness and setup.
  • The plugin MUST expose a separate dashboard KPI widget contribution.
  • The plugin MUST expose a settings page contribution.
  • The plugin SHOULD expose an issue detail contribution for GitHub metadata.
  • The issue detail contribution SHOULD prefer the slot-provided issue context before falling back to hook-provided host context. It SHOULD hide itself only when the host is not rendering an issue-scoped surface; when it expects issue context but cannot resolve the canonical Paperclip issue id, it SHOULD render compact troubleshooting details instead of disappearing. When the current Paperclip issue has no linked GitHub issue or pull request, it SHOULD render a compact manual-link fallback instead of an inert empty state.
  • The issue detail contribution SHOULD allow operators to manually link an unlinked Paperclip issue to either a GitHub issue or a GitHub pull request by entering either a number or a full GitHub URL. Number-only entries SHOULD resolve against the issue's mapped Paperclip project repository; full URLs SHOULD be allowed when the referenced repository is mapped to that project.
  • A manual GitHub issue link for a mapped repository MUST write the same issue-link entity and import-registry entry used by normal GitHub issue imports. A manual GitHub pull request link MUST write the same pull-request link entity used by project Pull Requests page create/link flows.
  • Agent tool links MAY target third-party repositories that are not mapped to the Paperclip issue's project. Those links MUST still write company-scoped durable issue-link or pull-request-link entities, and sync MUST use those entities as targeted worklist entries rather than requiring a repository mapping.
  • The issue detail contribution SHOULD allow operators to unlink a linked Paperclip issue from GitHub. Unlinking MUST remove the link from active worker resolution, remove any matching import-registry entry, clear GitHub Sync origin targets and hidden import markers from the Paperclip issue where possible, and leave both the Paperclip issue and GitHub item intact.
  • Agent-facing tools MUST NOT expose an unlink operation for issue-link or pull-request-link metadata. Only operator UI actions and internal sync repair paths such as an issue transfer to an unmapped repository may tombstone link metadata.
  • The issue detail contribution SHOULD include GitHub-marked issue-scoped action buttons alongside the GitHub deep links so operators can refresh that imported issue from the same panel.
  • The issue detail contribution SHOULD show the GitHub issue creator with a compact avatar treatment consistent with the pull request page.
  • When a linked pull request belongs to a different repository than the linked issue, the issue detail contribution and sync-created comment annotations SHOULD render that pull request using its actual repository URL and a label that makes the cross-repository link clear.
  • The plugin SHOULD expose a project sidebar item that opens a project-scoped Pull Requests page for the mapped repository and can show the current open pull request count for mapped projects through a lightweight count read instead of the heavier summary-card metrics path. Paperclip 2026.831 hosts do not mount projectSidebarItem contributions (streamlined sidebar, PAP-12472); the contribution stays declared for hosts that render it, and the page route MUST remain reachable without it.
  • The project pull request sidebar count, page, and metrics reads SHOULD tolerate saved mappings that are missing either the company id or the project id when the active Paperclip project context still identifies the intended mapping safely, and they SHOULD also fall back to the active project's bound GitHub repository when no saved sync mapping exists but the project workspace already defines that repository.
  • The project Pull Requests page SHOULD render live open pull request data for the mapped repository, including checks, an explicit up-to-date branch state, target branch badges, review summary, unresolved review-thread state, non-review comment counts, last-updated timestamps, Paperclip issue linkage, and quick actions.
  • The project Pull Requests page SHOULD include an Up to date column that distinguishes pull requests already current with the base branch from pull requests that are behind but can be updated cleanly and pull requests that need conflict resolution, and it SHOULD render that status from explicit branch-comparison data when GitHub provides it; when GitHub cannot confirm branch freshness, the queue SHOULD show an unknown state instead of assuming the branch is current.
  • The project Pull Requests page SHOULD expose a deterministic Update branch action for pull requests in the clean behind-base state, and it SHOULD keep conflict cases out of that direct path so they can be handled separately.
  • The project Pull Requests page SHOULD expose a Copilot quick-action menu that posts @copilot pull request comments for Fix CI on failing pull requests, Rebase on behind-with-conflicts pull requests, and Address review feedback on pull requests with unresolved review threads, while Review SHOULD use GitHub’s native reviewer-request flow for Copilot instead of a plain comment.
  • The project Pull Requests page SHOULD label the review-summary table column as Approvals, surface inline review, quick-approve, and quick-request-changes actions there when review submission is allowed, and keep approval, change-request, CI rerun, merge, close, and resolved-thread icon colors consistent with the corresponding queue and detail actions.
  • The project Pull Requests page SHOULD only show a pull request action when the configured GitHub token has been verified to hold the permission required for that action on the mapped repository; when permission audit data is unavailable, the page SHOULD fail closed and hide the action instead of assuming access.
  • The project Pull Requests page SHOULD surface total, mergeable, reviewable, and failing summary counts and let operators filter the table from those cards.
  • The project Pull Requests page SHOULD only treat a pull request as mergeable when it targets the repository's current default branch, has passing checks, has at least one approval, has no outstanding changes-requested reviews, and has no unresolved review threads.
  • The project Pull Requests page SHOULD keep KPI-triggered filtered views fast by reusing cached repo-wide filter indexes and fetching only the visible filtered rows instead of rebuilding every row summary on each click.
  • The project Pull Requests page SHOULD favor repository-scoped caches for totals, KPI aggregates, and per-pull-request review or CI insights, and SHOULD expose an explicit refresh path that invalidates those caches on demand.
  • The project Pull Requests page SHOULD paginate the queue in batches of 10 rows.
  • The project Pull Requests page SHOULD keep the visible queue sorted by the most recently updated pull requests first.
  • The project Pull Requests page SHOULD deep-link row icons to the relevant GitHub resource where possible.
  • The project Pull Requests page SHOULD render markdown and only sanitized, allowlisted inline HTML in pull request descriptions and comments instead of showing raw author text.
  • The pull request markdown renderer MUST strip event-handler attributes, inline styles, executable or embedded elements, and unsafe URL schemes, and SHOULD limit inline HTML support to non-executable formatting and link elements such as a, code, em, strong, b, i, br, span, sub, and sup; allowed attributes SHOULD stay limited to safe link metadata such as href, title, and target on a, plus class on span where markdown-compatible formatting needs it.
  • The project Pull Requests page SHOULD include a compact inline comment composer in the bottom detail pane.
  • The project Pull Requests page SHOULD support modal quick actions for commenting, reviewing, re-running CI, and confirming close actions in addition to merge when the pull request state allows them, while keeping Copilot requests as lightweight inline menus instead of separate modal flows.
  • The review modal SHOULD support comment-only, approve, and request-changes submissions so operators can match GitHub’s review outcomes without leaving the queue.
  • When GitHub rejects a pull request comment or review action, the worker and UI SHOULD preserve actionable permission or validation guidance instead of collapsing it to a generic error.
  • When a pull request is linked to a Paperclip issue, the project Pull Requests page SHOULD open that issue in a plugin-provided right drawer so operators can stay on the queue page, while still allowing explicit navigation away when desired.
  • When a pull request is not yet linked to a Paperclip issue, the project Pull Requests page SHOULD offer an inline create-issue action and wait for the returned Paperclip identifier before rendering the issue link or opening its drawer.
  • Paperclip issues created from the project Pull Requests page MUST be created with a GitHub Sync namespaced plugin pull-request origin and the canonical GitHub pull request URL as originId.
  • Paperclip issues created from the project Pull Requests page MUST explicitly start in todo and use Paperclip's standard work mode so host defaults for backlog parking or planning-mode work cannot change the queue semantics.
  • The settings page SHOULD audit the saved GitHub token against the mapped repositories in the active company and SHOULD warn when required pull-request-action permissions are missing or GitHub cannot verify them yet.
  • The plugin SHOULD expose manual sync buttons in the global toolbar and on mapped project/issue surfaces when the host renders those slot types.
  • The sync dashboard widget MUST summarize the current GitHub sync readiness and link to setup.
  • The separate KPI dashboard widget MUST show company KPI cards for open GitHub backlog, GitHub issues closed, and Paperclip pull requests created, including recent trend history and comparison against earlier periods when data exists.
  • When the latest sync run records issue-level failures, the settings page SHOULD expose a saved failure log with per-failure repository, issue, phase, raw error, and suggested next-step details, and compact surfaces SHOULD still surface at least the latest saved failure snapshot.
  • The settings page MUST render inside the real Paperclip host.
  • The plugin MUST include end-to-end automation that boots a disposable Paperclip instance, installs the plugin, and verifies the settings page renders.

Packaging and release requirements

  • The build pipeline MUST bundle the manifest and worker for Node execution and bundle the hosted UI separately for browser execution.
  • Local development SHOULD provide a watch-mode build and a local UI dev server for hosted-UI iteration.
  • The build pipeline MUST stamp the plugin manifest version from build-time package metadata rather than keeping a separately hardcoded manifest version.
  • The release workflow MUST derive the published version from the GitHub release tag and stamp that version into publishable package metadata before build and publish.
  • After a successful publish, the release workflow MUST sync that resolved release version back into the checked-in package.json on the release target branch so repository metadata reflects the latest published release.
  • The release workflow MUST run on a Node.js version that already satisfies npm trusted publishing requirements instead of relying on an in-job npm self-upgrade step.

Paperclip 2026.831 compatibility boundary

Paperclip 2026.831 makes plugin config company-scoped, re-enables plugin secret refs, routes agent tool execution through the host tool gateway, and adds optional capabilities that GitHub Sync does not need.

  • Plugin config is company-scoped. The worker MUST pass the company id to ctx.config.get(companyId) whenever a data, action, tool, job, or API-route path knows the company, MUST declare multiCompanyConfig: true because one worker serves every company on the instance, and MUST implement onConfigChanged(newConfig, { companyId }) by remembering the delivered config per company so proactive paths (scheduled sync, actions without a company) can still resolve company-keyed settings when the host cannot derive a scope. The worker MUST NOT read plugin config from onHealth(), which has no company scope. Startup config passed to setup() is empty; the worker MUST NOT depend on it.
  • Proactive worker-to-host calls (scheduled sync, webhook-free background work) are only authorized for companies that have a saved GitHub Sync plugin config row. When the host denies a company scope during a sync run, the worker MUST record a sync error that tells the operator to open GitHub Sync settings in that company and save once, instead of surfacing the raw host error.
  • The settings UI MUST read and write plugin config with the active company (GET /api/plugins/:id/config?companyId= and POST with companyId), MUST write secret refs as { "type": "secret_ref", "secretId" } bindings, and MUST keep the manifest instanceConfigSchema accepting both the binding and the legacy bare-UUID string so config rows migrated from older releases keep validating until they are re-mirrored.
  • Agent tool discovery and execution go through the host tool gateway with the company tool-access policy. Tool names remain <pluginId>:<tool>; the plugin MUST NOT assume its tools bypass that policy, and the KPI attribution endpoint remains a native plugin JSON route authenticated by the agent run token.
  • The host tool gateway is fail-closed: with no matching profile, grant or allow policy it denies by default, and plugin tools carry no connection or catalog id, so only tool_name or risk_level profile entries (or a profile with defaultAction: "allow") can grant them. The documentation MUST describe a working company-scoped tool profile recipe for all declared GitHub Sync tools.
  • The settings registration data MAY include a best-effort, read-only agentToolAccess summary reporting how many GitHub Sync tool names one sampled agent of the company can currently see. Because the host evaluates tool profiles per agent and agent-scoped bindings override company-scoped ones, the summary MUST identify the sampled agent and the settings page MUST present the warning as a single-agent sample rather than a company-wide verdict. The check MUST NOT fail settings loading: missing board access, missing agents, an unreachable worker Paperclip API URL, or a host that answers 403/404 MUST be reported as unavailable with a null count instead of an error.
  • Company export/import bundles carry no plugin section, so GitHub Sync mappings, plugin config, link entities, import registry, KPI history and interaction ledger do not survive an import. The documentation MUST state this limitation; automatic re-linking of an imported company is out of scope for this release.
  • The host's merged-PR confirmation sweep and the experimental GitHub MCP app definition MAY operate alongside GitHub Sync. GitHub Sync MUST remain the source of truth for mapped and linked Paperclip issue status, and MUST NOT delegate status routing to either surface.
  • GitHub Sync MUST NOT declare issue.interactions.read, issue.attachments.read, approvals.read, issue.comments.create_human_attributed, issue.interactions.respond, or approvals.respond until worker code actually uses those host surfaces; capabilities stay minimal and tied to real behavior.
  • The manifest MUST NOT declare a strict minimumHostVersion or minimumPaperclipVersion gate; compatibility is expressed through capabilities and worker fallbacks.
  • The 2026.831 streamlined main sidebar has no projectSidebarItem mount point. The plugin MAY keep declaring that slot, MUST NOT depend on it for reaching the project Pull Requests page, and disposable e2e verification MUST open that page by route while only asserting the sidebar link when the host renders it.

The boundaries adopted with Paperclip 2026.626 still apply. Paperclip 2026.626 external object references, task watchdogs, ask work mode, routine date variables, and built-in Hermes adapters are host/runtime capabilities. GitHub Sync MUST NOT declare a duplicate GitHub external.objects.* provider while the host ships a built-in GitHub external-object provider. Because that host provider now supersedes the plugin's generic comment-link rendering, GitHub Sync MUST NOT declare the legacy commentAnnotation UI slot for GitHub links. Synced descriptions, comments, and status-transition annotations SHOULD continue to include canonical GitHub issue and pull request URLs so the host provider can detect them, but GitHub Sync's mappings, plugin entities, sync jobs, and agent tools remain authoritative for routing mapped/linked Paperclip issue state.

Task watchdogs MUST NOT replace GitHub Sync's scheduled/manual PR status refresh. GitHub Sync MUST NOT create, read, update, delete, or auto-attach /api/issues/:id/watchdog configuration, and MUST NOT pass a watchdog field when importing or creating GitHub-backed Paperclip issues. Waiting on GitHub CI, mergeability, review threads, or maintainer approval is an external GitHub wait, not a stopped Paperclip task tree. GitHub Sync MAY coexist with operator-created task watchdogs, and its normal issue comments/status transitions SHOULD remain visible to host watchdog reconciliation. However, GitHub Sync MUST continue to drive issue status from GitHub snapshots and MUST NOT treat watchdog review issues as the source of truth for PR state. GitHub Sync tools are normal company-scoped plugin tools, not currently task-watchdog-scope-aware; a future host/plugin contract is required before mutating GitHub tools can enforce watched-subtree scope.