Skip to content

Watch for connector requests with a one-shot background watcher, not Monitor - #902

Open
robzolkos wants to merge 8 commits into
mainfrom
connect-one-shot-watcher
Open

robzolkos wants to merge 8 commits into
mainfrom
connect-one-shot-watcher

Conversation

@robzolkos

@robzolkos robzolkos commented Oct 13, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Replace the expiring Monitor watch with a one-shot background request watcher. Each invocation reads complete connector-output lines, returns unhandled requests once, and exits. The session reads its output, records the ids, starts the next watcher, and handles the requests.

  • Replays the output from the start, so requests arriving between watcher invocations are not skipped.
  • Ignores partial lines, deduplicates repeated ids, handles literal backslashes in paths, and refuses unusable inputs.
  • Supports --once to drain the output when the connector stops.
  • Updates the skill and post-compaction wording to describe the watcher. The existing skill-size checks remain enforced.

Verification

  • Full local bin/ci passes after rebasing onto current main.
  • 14 focused regressions are committed to the existing BATS suite: usage, missing/empty inputs, handled-file creation, handled ids and exact matching, duplicate lines, other event types, partial lines, escaped content, literal paths, unusable handled paths, loss of the handled file between startup and scanning (both modes), and delivery after a new line arrives.
  • Mutation checks reject removing the complete-line guard, removing per-run deduplication, and passing a literal handled path through awk -v.
  • Existing skill layout and command-drift checks pass. No new testing harness or server is introduced.

Review boundary

The session must restart the watcher after each completion; it is not an independent supervisor for an unavailable session. Recording handled ids before dispatch also retains the documented interruption trade-off. No fresh real-session, macOS-runtime, laptop-sleep, or expired-login recovery claim is made by these script tests.

The newer alternative in #958 addresses sleep/expired-login recovery with a recurring heartbeat and monitor re-arming. These are alternative approaches and should not both land unchanged. This PR is being verified on its own scope, not presented as covering that broader recovery scenario.

@robzolkos
robzolkos requested a review from a team as a code owner October 13, 2026 22:24
Copilot AI balanced review requested due to automatic review settings October 13, 2026 22:24
@github-actions github-actions Bot added commands CLI command implementations skills Agent skills labels Oct 13, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Handled-file validation and post-compaction watcher guidance can cause replayed requests or leave sessions unwatched.

3 open findings
What changed in this PR

Replaces expiring Monitor-based connector request handling with a one-shot polling watcher.

Changes:

  • Adds request filtering, deduplication, and drain support.
  • Updates connector skill lifecycle instructions.
  • Renames the post-compaction monitor reference.

[!TIP]
If you aren't ready for review, convert to a draft PR.
Click "Convert to draft" or run gh pr ready --undo.
Click "Ready for review" or run gh pr ready to reengage.

File Description
skills/​basecamp-connect/​watch-requests.sh Implements the one-shot watcher.
skills/​basecamp-connect/​SKILL.md Documents watcher operation and shutdown.
internal/​commands/​agent_hook_connector.go Updates post-compaction guidance.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread internal/commands/agent_hook_connector.go Outdated
Comment thread skills/basecamp-connect/watch-requests.sh Outdated
Comment thread skills/basecamp-connect/watch-requests.sh
Copilot AI balanced review requested due to automatic review settings October 13, 2026 22:33

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The watcher can remain alive indefinitely after losing access to its connector output file.

1 open finding
2 resolved since last review
Previously missed (1)

In code that hasn't changed since last review

Medium severity Watcher loops forever when task file becomes unreadable

skills/​basecamp-connect/​watch-requests.sh:28

The connector output is checked only before polling starts. If that background-task file is later removed or becomes unreadable, this redirection fails and the arithmetic expansion yields zero, so the watcher stays alive and sleeps forever instead of reporting failure. That also defeats the compaction notice's liveness check because the task still appears running while it can no longer observe requests. Revalidate the file on each poll and exit 2 when it cannot be read.

🧠 Review effort: Balanced

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The documented watcher commands break when expanded paths contain apostrophes.

1 open finding
Previously missed (1)

In code that hasn't changed since last review

Medium severity Shell-quote expanded watcher paths to handle apostrophes

skills/​basecamp-connect/​SKILL.md:84

The expanded skill directory and connector output path are inserted between literal single quotes. If either valid path contains an apostrophe, this command is syntactically invalid and the watcher never starts (for example, Bash reports an unmatched quote for a skill path such as skill'copy). Instruct the session to shell-quote each expanded path, including escaping embedded apostrophes, rather than wrapping raw placeholders in fixed quotes.

This issue also appears on line 553 of the same file.

🧠 Review effort: Balanced

@robzolkos

Copy link
Copy Markdown
Collaborator Author

🤖 Review status on e1d4116

Reviewers and the commit each read:

  • Pi (openai-codex/gpt-6.1-sol, xhigh) read 32d2a31. Its findings and what I did about each are in the PR description.
  • Copilot read 7667cbf, b42a8df and e1d4116. Its latest review is on the current head.
  • cubic skipped this PR.

Copilot findings fixed:

Declined on merit: an apostrophe in the expanded skill or output path breaking the single-quoted commands (review body on e1d4116, SKILL.md:84 and :553).

  • The skill's quoting rule already says to write a quote inside a value as '\''.
  • The pattern predates this PR: tail -f -n +1 '<connector-output-file>' and `${CLAUDE_SKILL_DIR}/subagent.md`.
  • Both paths come from the harness, which sanitizes the session directory name.
  • A fix here would also belong in every other command in the skill, so it's a separate change if anyone wants it.

Open for a maintainer: commit the watcher's scenario suite as a test. It's out of the scope I was given (the skill text and its script). I'll add a BATS file under e2e/ if asked.

bin/ci is green locally on e1d4116. It needs a human merge.

Copilot AI balanced review requested due to automatic review settings October 14, 2026 17:13
@robzolkos
robzolkos force-pushed the connect-one-shot-watcher branch from e1d4116 to c5bf320 Compare October 14, 2026 17:13

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Losing access to the handled file during polling can replay previously handled requests and dispatch duplicate work.

2 open findings

🧠 Review effort: Balanced

Comment thread skills/basecamp-connect/watch-requests.sh Outdated
…Monitor

The skill armed the Monitor tool with `persistent: true`. Claude Code 2.1.271
removed that option: every watch now expires within 30 minutes, so a session
has to re-arm it. Re-arming and skipping handled ids with `grep -v` loses
requests in a different way. In Claude Code's Bash, `grep` is the embedded
ugrep, and `ugrep -v` holds each line on a stream until the next one arrives,
`--line-buffered` or not. The newest request then waits for the next one.

watch-requests.sh reads the connector's output from the start, prints the
request lines whose event_id the handled file lacks, and exits. The session
records each id, starts the watcher again, and handles the lines. The notification
is the exit itself, so no stream filter sits between a line and the session,
and reading from the start leaves no gap between watchers. The watcher reads only
complete lines, and the handled file lives outside the run, so a line
reprinted after a crash is still skipped.
…t, and fail closed on the handled file

A request printed just before the connector exits could sit in the old
output file after the watcher moved to the new one. watch-requests.sh --once
checks the old file a last time, without needing timeout(1), which macOS
lacks.

The watcher's completion notice names its output file rather than carrying
the lines, so the skill says to read them from there.

awk -v decodes backslashes, so the handled path reaches awk through ENVIRON.
A handled file the watcher can't create or read now exits 2 instead of
reporting every request as new.

The post-compaction notice said the session's monitor kept running. It now
names the request watcher.
…he watcher

A directory or a read-only file passed touch and -r, so the watcher ran
against a handled file the session could never record into, and every
restart replayed the same requests. It now requires a regular file it can
read and write.

The post-compaction notice said everything kept running. The watcher exits
on each request, so it may have exited during the compaction. The notice now
says to check it, and to read its output and start it again if it has
exited.
The output file was checked once, before polling. If it went away later,
wc failed, the line count read as zero, and the watcher slept forever while
looking alive. Each poll now checks the file and exits 2 if it can't be read.
Copilot AI balanced review requested due to automatic review settings October 23, 2026 20:16
@robzolkos
robzolkos force-pushed the connect-one-shot-watcher branch from c5bf320 to d5b976f Compare October 23, 2026 20:16
@github-actions github-actions Bot added the tests Tests (unit and e2e) label Oct 23, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The Claude Code background-task completion and restart lifecycle still needs human validation beyond the script regressions.

2 open issues

Review effort: Balanced

Copilot AI balanced review requested due to automatic review settings October 23, 2026 20:46
@robzolkos

Copy link
Copy Markdown
Collaborator Author

Rebased and added committed coverage to the existing BATS suite. All 14 watcher tests and full local CI pass. A handled-file disappearance between startup and scanning now fails closed in both polling and --once mode rather than replaying work. The skill still fits the existing compaction/layout limits. Current head: 20449f0. The alternative in #958 remains a separate review choice; this PR does not claim that broader session-recovery behavior.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Background-task notifications and session-driven watcher re-arming still need human validation in Claude Code beyond the script-level regressions.

2 open issues

Review effort: Balanced

@robzolkos

Copy link
Copy Markdown
Collaborator Author

Ready for human review on 20449f0: local and hosted CI are green and both remaining script/test findings are fixed and resolved. Copilot reported on this exact head; it asks for human validation of the Claude Code task-completion/re-arm lifecycle, not another script fix. Cubic could not provide a fresh pass because its monthly quota is exhausted. The remaining decision is this one-shot approach versus the heartbeat/re-arm alternative in #958. The BATS regressions do not claim a fresh real-session, sleep, or expired-login test. This is ready to review, not an instruction to merge both alternatives.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

commands CLI command implementations skills Agent skills tests Tests (unit and e2e)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants