Repository navigation
feat: record_on_issue — let Slack chat runs comment on in-scope issues (0.12.0) - #20
Merged
Merged
Conversation
…issues A plugin-started chat run has no issue in its host run context, so the host's cross-issue guard refuses every comment it makes, including on the thread's own issue. record_on_issue writes through the plugin's createComment path instead, which skips that guard, and enforces the containment in the plugin: - only runs this plugin bound to a Slack conversation (run -> thread binding written from sendMessage's runId, agent id checked, expires 30 min after the turn settles, 24 h hard cap) - target must be the thread's own issue (plugin thread->issue link, or an issue link on paperclipBaseUrl in a root this bot posted, read from text and Block Kit links) or an issue a human named in the thread; bot and foreign-bot text never widen scope - roots whose words an agent chose (slack_post_message, ask_human, top-level DM replies) are recorded and never count as issue-linking; roots older than the 90-day record window don't either - 20 writes per run (mirrors CROSS_ISSUE_INFLUENCE_LIMIT), serialized per run, dedupe checked before the cap - refuses issues under a trust preset (the host would quarantine an agent comment there; this path can't tag it) - UUID-resolved target, agent-attributed comment, fixed footer with thread permalink and run id, activity log + code-tagged metrics, best-effort idempotent assignee wake, never the caller Adds the issues.read capability (identifier -> UUID and assignee), which needs operator re-approval on upgrade. Bumps to 0.12.0. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…6.16.0, fast-uri 3.1.8 The high-severity undici advisory (WebSocket permessage-deflate DoS) is in the Socket Mode transport (@slack/bolt -> @slack/socket-mode -> undici) and fails CI's npm audit step. Lockfile-only, in-range bumps. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements
docs/2026-09-30-slack-record-on-issue-spec.md(paperclip repo), amended after an adversarial review against server 2026.930.0-canary.3 and the prod host (2026.916.0-canary.0).Problem
A plugin-started Slack chat run has no
issueId/taskIdin its run context (plugin-host-services.jssendMessage), andobserveCrossIssueInfluencethrowscross_issue_influence_run_context_requiredbefore it compares source and target. So the Slack agent can't write to any issue, including the thread's own. Seen on POL-3267 (2026-09-30) and POL-3099 (2026-09-29, where Raúl's "the fix implemented was PR #53" had to be relayed through a child issue, POL-3206).Change
New agent tool
record_on_issue({ issue, body, wakeAssignee? }). It writes throughctx.issues.createComment, which doesn't run the cross-issue guard, so the plugin enforces the containment itself:company_mismatchsendMessage's runId; live until 30 min after the turn settles, 24 h cap)not_a_slack_chat_runissue_not_foundlow_trust_targetpaperclipBaseUrlissue link in a root this bot posted, read from text and Block Kit links), or a human named it in the thread or the triggering messageissue_not_in_thread_scopeok,duplicate: truerun_write_cap_exceededChanges from the spec, from the review:
slack_post_message, which would fake rule 4a.2. Top-level posts with agent-written text (slack_post_message,ask_human, top-level DM replies) are now recorded and never count as issue-linking. Roots older than that 90-day record window don't count either.paperclip-escalateposts directly withchat.postMessage, so real escalations still work.issues.readcapability: added and required. The host'screateCommenthands the raw id toaddComment, so it needs the UUID, and the plugin also needs the assignee. Operator re-approval is required on upgrade.thread-issue:<channel>:<ts>key, written with the issue-created notification, replaces scanning the issue-thread index.fromAnyBotandblockLinkson thread messages, andgetPermalink(chat.getPermalink, no extra scope).What is written: an agent-attributed comment (
authorAgentId) with a footer the agent can't suppress:Relayed from Slack · <thread permalink> · run <runId>. Then an activity-log entry (metadata.action: slack.record_on_issue, with the scope rule), metrics tagged withcodeonly, and a best-effort assignee wake (idempotency key per run and issue, never the caller).Rollout (not part of this PR)
record_on_issueinstead ofPOST /api/issues/:id/commentsin chat runs. The file is on the host:~paperclip/.paperclip/instances/default/companies/79544d4d-2f8a-459b-a316-cef2d510566e/agents/e2d936fd-d104-481e-bb34-a3dacd31367f/instructions/AGENTS.md.issues.read, restartpaperclip.service.paperclipBaseUrlishttps://scc.polygon.org, since rule 4a.2 matches only that origin.issue_not_in_thread_scope. This also confirms the tool call'srunIdequals thesendMessagerunId.Testing
tests/record-on-issue.test.ts, including a regression built from the POL-3099 thread. Mutation checks: removing the agent-post exclusion, the agent-id check, the bot-text filter, the cap, or the age limit each fails a test.🤖 Generated with Claude Code