Skip to content

Let the connector do the work itself, on the coding agent you choose - #1026

Merged
robzolkos merged 11 commits into
mainfrom
connect-runner
Nov 12, 2026
Merged

robzolkos merged 11 commits into
mainfrom
connect-runner

Conversation

@robzolkos

@robzolkos robzolkos commented Nov 11, 2026 •

Copy link
Copy Markdown
Collaborator

What this does

basecamp connect -P <profile> --orchestrator <agent> makes the connector do the work itself, with no session reading its output. Each trusted request goes to a headless session of the coding agent named. That session follows the basecamp-connect skill as it ships and hands the work to a worker, a session of its own, which replies in Basecamp as the agent.

Without the new flags the connector behaves as it does today: it prints request lines for the session that started it. connect stays hidden.

Why

The skill needs a Claude Code session left open, because it relies on two things that harness has: a monitor that wakes the session for each request line, and background subagents. The connector now supplies both from the CLI, so the same Agent Skill runs on other coding agents and keeps running with no session open.

How it is put together

  • internal/connector/runner (new). An adapter per coding agent CLI (the arguments of a headless turn and how its event stream reads), the orchestrator loop, the workers, the state file and a unix socket. There are three built-in adapters; a new one is a new adapter plus a stream fixture.
  • HandoffOptions.Deliver. The handoff gives the runner each request after writing its line and before closing its record, so a crash repeats a request rather than losing it, provided the connector starts again within the handoff's grace of a minute. Nil for every run without the new flags.
  • Commands the orchestrator runs, over the socket: connect dispatch, workers list|send|stop, say, stop, restart.
  • runner.json, beside connect.json: rules that choose a worker's coding agent, model and effort by repo, project, card table, to-do list or Ping, and what the connector was last started with (--run reuses it).
  • The skill. SKILL.md gains one section at the end for this path, and its opening no longer says the connector requires Claude Code. subagent.md is unchanged. The runner gives both files to its agents verbatim and adds only a table mapping the mechanisms they name onto its commands.

Worth a reviewer's attention

  • Permissions. --permissions full is the default: each CLI is started with its permission prompts off, because a headless turn has nobody to answer one. guarded starts each under its own unattended guardrails (Claude Code's auto mode; Codex's sandbox with automatic review) and refuses a CLI that has none.
  • The runner's commands inside a sandbox. An agent the connector starts is told which runner started it through two environment variables, the socket's path and the profile, so dispatch and the rest reach the socket without reading connect.json, whose ownership cannot be checked from inside a coding agent's sandbox. The check itself is unchanged. The socket is only used in a directory that is the person's own and closed to everyone else, which is what decides who may use it.
  • Follow-ups. A later request on the same card, to-do, message or chat goes to the worker that handled the first, in the same session. A new worker starts only when that session cannot take it.
  • Stops and crashes. A worker a stop interrupted is continued at the next start. A process a crash left running is ended by its recorded process group and confirmed gone before its session is continued, and a start that cannot confirm it does not start. While the connector's hold stands, no agent is started.

Verified

  • bin/ci on a clean checkout of this branch.
  • An opt-in test against the installed CLIs (go test -tags runner_live ./internal/connector/runner -run TestInstalled): a turn answers, a second turn continues the session, a session that no longer exists fails cleanly, and under guarded both Claude Code and Codex commit in a repo on a new and a resumed session.
  • Live, against a real Basecamp project on Linux, with Claude Code and Codex each as orchestrator and as worker, under full and guarded: a question answered in place, repo work with a worktree, commit and pushed branch, a follow-up continuing the same worker, a restart in the middle of a task, a rule choosing the worker by card table and by repo, and --run from kept settings.
  • The edited skill in a fresh Claude Code session still takes the original path: it started the plain connector, armed its monitor, and a background subagent replied.

Not verified

  • macOS.
  • Pings: every live run was narrowed to one project.
  • A pull request on a hosted remote: pushes went to a local one.
  • A run longer than a few minutes, and a hard kill of the connector outside the unit test.
  • The skill's model evals, which need an API key this was not run with.
  • The new skill section followed by a session that is not Claude Code.

Copilot AI balanced review requested due to automatic review settings November 11, 2026 22:08
@github-actions github-actions Bot added commands CLI command implementations tests Tests (unit and e2e) skills Agent skills docs labels Nov 11, 2026
@robzolkos
robzolkos marked this pull request as ready for review November 11, 2026 22:10
@robzolkos
robzolkos requested a review from a team as a code owner November 11, 2026 22:10

@cubic-dev-ai cubic-dev-ai Bot 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.

2 issues found across 26 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="internal/commands/connect_runner_test.go">

<violation number="1" location="internal/commands/connect_runner_test.go:170">
P3: Don't call `require` inside the `require.Eventually` condition. A failure there runs on the wrong goroutine and surfaces as a generic 20s timeout, and an unchecked type assertion panics the test binary. Use `require.EventuallyWithT` with `assert` calls, or poll in the test goroutine and assert the final state there.</violation>
</file>

<file name="internal/connector/runner/workers.go">

<violation number="1" location="internal/connector/runner/workers.go:293">
P2: `Send` can revive a stopped worker whose turn is still running, which starts a second turn on the same session. Reject stopped workers before appending the message.</violation>
</file>

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread internal/connector/runner/workers.go Resolved
Comment thread internal/connector/runner/runner.go Resolved
Comment thread internal/connector/runner/runner.go Resolved
Comment thread internal/connector/runner/doc.go Resolved
Comment thread internal/connector/runner/store.go Resolved
Comment thread internal/commands/connect_runner.go Resolved
Comment thread skills/basecamp-connect/SKILL.md Resolved
Comment thread internal/connector/runner/socket.go Resolved
Comment thread internal/connector/runner/store.go Resolved
Comment thread internal/connector/runner/workers.go Resolved
Comment thread internal/connector/runner/runner.go Resolved
Comment thread internal/connector/runner/workers.go Resolved
Comment thread internal/connector/runner/socket.go Resolved

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

Unresolved critical issues can disable an active runner’s guardrails, allow duplicate or orphaned command execution, and lose accepted requests.

9 open issues
What changed in this PR

Adds an optional headless runner so the connector can coordinate Basecamp work through Claude Code, Codex, or Pi without an open chat session. The existing print-only connector flow remains the default.

Changes:

  • Adds agent adapters, a persistent inbox, reusable worker sessions, and recovery handling.
  • Introduces runner control commands, routing rules, saved startup settings, and permission modes.
  • Embeds the connector skill and adds documentation, unit coverage, and opt-in live-agent tests.

[!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/​embed.go Embeds the connector workflow and worker instructions.
skills/​basecamp-connect/​SKILL.md Documents unattended operation and runner controls.
internal/​connector/​runner/​workers.go Implements worker dispatch, continuation, stopping, and reporting.
internal/​connector/​runner/​turn.go Runs agent processes and reads their output streams.
internal/​connector/​runner/​store.go Persists sessions, requests, inbox items, and workers.
internal/​connector/​runner/​spec.go Defines agent settings, permissions, and routing rules.
internal/​connector/​runner/​spec_test.go Tests configuration validation, precedence, and routing.
internal/​connector/​runner/​socket.go Provides the local runner control protocol.
internal/​connector/​runner/​runner.go Coordinates orchestration, delivery, recovery, and permissions.
internal/​connector/​runner/​runner_test.go Tests runner lifecycle, recovery, and session reuse.
internal/​connector/​runner/​instructions.go Maps skill mechanisms onto runner commands.
internal/​connector/​runner/​installed_test.go Adds opt-in tests against installed coding agents.
internal/​connector/​runner/​fake_agent_test.go Supplies scripted agents for runner tests.
internal/​connector/​runner/​doc.go Documents runner architecture and persistence.
internal/​connector/​runner/​adapter.go Implements Claude Code, Codex, and Pi adapters.
internal/​connector/​runner/​adapter_test.go Tests agent arguments and stream parsing.
internal/​connector/​handoff.go Adds runner delivery before closing ledger records.
internal/​connector/​handoff_test.go Tests delivery ordering and failure retries.
internal/​commands/​connect.go Registers runner commands and expands connector help.
internal/​commands/​connect_runner.go Adds runner flags, setup helpers, and control commands.
internal/​commands/​connect_runner_test.go Tests runner settings and command integration.
internal/​commands/​connect_run.go Integrates runner startup, logging, delivery, and shutdown.
internal/​commands/​connect_process_unix.go Supports restarting through process replacement.
internal/​commands/​connect_process_other.go Reports unsupported-platform restart behavior.
AGENTS.md Documents runner development conventions and architecture.
.surface-skill-drift Allows documented references to hidden runner commands.

Review effort: Balanced

Comment thread internal/commands/connect_run.go Resolved
Comment thread internal/commands/connect_run.go Resolved
Comment on lines +288 to +290
if opts.Deliver != nil {
if err := opts.Deliver(ctx, line); err != nil {
return fmt.Errorf("connector: deliver event %d: %w", record.ID, err)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Not changed here, and the comments that overstated it are corrected in 20b40d0. The age guard is the connector's standing rule that a request older than a minute at a start is not run late, and it applies with a runner as it does without. What Deliver adds is narrower than the comments said: a request written but not yet kept when the connector crashed is handed off again by a start within that grace. Exempting undelivered records from the guard would run requests late after a long outage, which changes the handoff's contract and is better decided on its own. Leaving this thread open for a maintainer's call.

Comment thread internal/connector/runner/runner.go Resolved
Comment thread internal/connector/runner/runner.go Resolved
Comment thread internal/connector/runner/socket.go Resolved
Comment thread internal/connector/runner/store.go Resolved
Comment thread internal/connector/runner/workers.go Resolved
Comment thread internal/connector/runner/workers.go Resolved
Copilot AI balanced review requested due to automatic review settings November 11, 2026 22:31

@cubic-dev-ai cubic-dev-ai Bot 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.

All reported issues were addressed across 15 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread internal/commands/connect_runner.go Resolved
Comment thread internal/connector/runner/socket.go Resolved
Comment thread internal/connector/runner/spec_test.go Resolved
Comment thread internal/commands/connect_runner.go Resolved

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

Unresolved critical defects can lose accepted requests after delivery failures, resume sessions alongside surviving processes, and allow symlink attacks to redirect connections to attacker-controlled sockets.

5 open issues
3 previously missed issues

In code that hasn't changed since last review

Medium severity Restore worker state when saving a follow-up fails

internal/​connector/​runner/​workers.go:219

[P2] If saving a follow-up fails, the reused worker keeps the appended event and queued state, but an idle worker never reaches r.start. Retrying then returns existing=true, leaving the request stranded; a running worker can instead consume a handoff reported as failed. Restore the worker's previous state before returning the save error.

Medium severity Restore worker state when saving a message fails

internal/​connector/​runner/​workers.go:319

[P2] A failed save leaves the new message and queued state in memory, but skips starting a finished worker. A retry sees it as live and also skips r.start, stranding both messages; a running worker can instead execute a send reported as failed. Restore the previous worker state and prompt slice before returning the error.

Medium severity Treat execution failures as unknown before retrying

internal/​connector/​runner/​workers.go:557

[P2] A timeout or execution error can happen after a worker posts a reply or pushes changes, so this report cannot claim that nobody replied. instructions.go:85 explicitly tells the orchestrator to redispatch these failures with --again, risking duplicate effects. Update both the report and that instruction to treat completion as unknown and require checking the thread and repository before retrying.

5 resolved since last review

Review effort: Balanced

Comment thread internal/connector/runner/socket.go Resolved
Copilot AI balanced review requested due to automatic review settings November 11, 2026 22:45

@cubic-dev-ai cubic-dev-ai Bot 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.

1 issue found across 8 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="internal/connector/runner/runner.go">

<violation number="1" location="internal/connector/runner/runner.go:550">
P1: This checks the hold only before an orchestrator turn starts; a hold set during the turn does not stop or gate the running agent, which can continue dispatching or posting while the hold stands. Monitor hold changes during turns and stop or gate agent actions until release.</violation>
</file>

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread internal/connector/runner/runner.go Resolved
Comment thread internal/connector/runner/runner.go Resolved
Comment thread AGENTS.md Resolved
Comment thread internal/connector/runner/runner.go Resolved

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

Process recovery can resume sessions without confirming old commands have stopped, while unresolved workers remain reusable, risking overlapping execution and overwritten recovery records.

3 open issues
2 previously missed issues

In code that hasn't changed since last review

Medium severity Restore worker state when follow-up save fails

internal/​connector/​runner/​workers.go:219

If saving a follow-up fails, the previous worker is left mutated in memory: it already contains this event and, if it was idle, is now queued, but r.start was never reached. Retrying the dispatch then finds the event in workerFor and returns success without starting anything, leaving the accepted request stuck. Restore the worker's previous state when the save fails, as the new-worker path already rolls back its insertion.

Medium severity Roll back worker mutations when message save fails

internal/​connector/​runner/​workers.go:319

A failed save leaves the appended message and queued state in memory even though Send reports failure. For a finished worker, no goroutine is started, and a retry now sees a live worker and skips r.start again, so it remains stuck until restart. For a running worker, the rejected message can still execute and be duplicated by a retry. Roll back the worker mutation before returning the save error.

4 resolved since last review

Review effort: Balanced

Comment thread internal/connector/runner/runner.go Resolved
Comment thread internal/connector/runner/runner.go Resolved
Copilot AI balanced review requested due to automatic review settings November 11, 2026 23:10

@cubic-dev-ai cubic-dev-ai Bot 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.

All reported issues were addressed across 11 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread internal/connector/runner/socket.go Resolved
Comment thread internal/commands/connect_runner.go Resolved

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

Human assessment is needed because process-persistence and termination gaps can leave untracked agents running alongside retries, while save failures can also stall or duplicate work.

1 open issue
2 resolved since last review

Review effort: Balanced

Copilot AI balanced review requested due to automatic review settings November 11, 2026 23:26

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

Critical risks in process-record persistence, descendant termination, and recovery of pending requests require human assessment.

1 open issue

Review effort: Balanced

The handoff writes a trusted request to stdout and then closes its record,
which is all a reader of the lines needs. A run that does the work itself
needs the request kept somewhere of its own first: closed before it is kept,
a crash between the two loses a request that was already acknowledged.

HandoffOptions.Deliver is called after the line is written and before the
record is closed, and returns once the request is kept. A delivery that fails
leaves the record open, so the request is delivered again. Nil delivers
nowhere, which is every run today.
…gent's CLI

The basecamp-connect skill runs in a Claude Code session and leans on two
things only that harness has: a monitor that wakes the session for each
request line, and background subagents. The runner supplies both from the CLI,
so the same skill can run on any coding agent that takes a prompt without a
terminal, runs shell commands and continues an earlier session.

Each request the connector hands off is kept in the runner's state and given
to an orchestrator, one turn of a headless session at a time. The orchestrator
follows SKILL.md as it ships and hands the work to a worker, a session of its
own that follows subagent.md and reports back as another turn. The runner adds
only a table that maps the mechanisms the skill names onto its commands.

An adapter is one CLI: the arguments of a turn and how its event stream reads.
A turn is one process, started through driver.StartWorker as the leader of a
process group the runner can end whole.

- A later request on the same card, to-do, message or chat goes to the worker
  that handled the first, continued in its session, and waits its turn if that
  worker is busy. A new worker starts only when that session cannot take it.
- A worker a stop interrupted is continued at the next start and told so. A
  process a crash left running is ended, by its recorded process group, before
  its session is continued.
- runner.json, beside connect.json, chooses a worker's coding agent, model and
  effort by repo, project, card table, to-do list, containing recording or
  Ping, and keeps what the connector was last started with.
- Permissions are one switch. Full starts each CLI with its prompts off, since
  a headless turn has nobody to answer one. Guarded starts each under its own
  unattended guardrails, and refuses a CLI that has none.

The adapters are held to the installed CLIs by an opt-in test:
go test -tags runner_live ./internal/connector/runner -run TestInstalled
…ts use

basecamp connect -P <profile> --orchestrator <agent> does the work itself
instead of printing requests for a session to read. --worker names another
coding agent for the work, the model and effort flags choose those, and
--permissions chooses full or guarded. What a start names is kept for the
profile, and --run starts with it. Without any of these the connector is what
it was.

The orchestrator's tools are commands that reach the running connector over a
unix socket in its state directory: dispatch hands a request to a worker,
workers list, send and stop see and steer them, say talks to the orchestrator
from a terminal, and stop and restart end the connector or start it again.

An agent the connector starts is told which runner started it, so these
commands reach the socket from inside a coding agent's sandbox, where the
ownership of connect.json cannot be checked. The check is unchanged.
The skill said running the connector requires Claude Code. Watching it from a
session still does. A new section, after everything a session following the
original flow reads, says how to start the connector with an orchestrator
instead: which coding agent, that the choice is kept, that it has to be started
where it outlives the session, what full and guarded permissions mean, and the
commands for checking on it.

The per-request steps stay inside the compaction budget, and the new hidden
commands and flags are acknowledged in the drift baseline with the rest of
connect.
One request, one worker. Dispatch let go of its lock to read what a request
sits under and did not ask again, under the lock, whether the event had got a
worker meanwhile, so two dispatches arriving together could start two. A
worker also has one goroutine now, whatever it is told: a message sent just
after a stop, before the stopped turn had ended, started a second one on the
same session.

A leftover process is always ended. Starting with another orchestrator reset
the session and, with it, the record of a process the last run had left, which
then ran on beside the new one.

What never ran is not counted. A turn refused under guarded permissions
reached no agent, and no longer uses up one of a message's attempts. A `say`
that could not be saved is taken back out, so a retry is not answered twice.

Requests still waiting, or being worked on, are not pruned with the history. A
rule's relative repo is refused when the file is read, since it could never
match. What a request sits under is cached only when it was read, so a rule
added later still gets its answer, and a card on hold is followed to its
column and card table, which its On Hold section does not name.

The socket no longer gives up on the first failed accept, and a client that
sends half a request no longer holds a stop open. Standard input past its
limit is refused rather than cut. A dispatch waits as long as its lookups can
take. What a start names is kept once the start has its lock, not before.

A failed turn's stderr has the agent's environment taken out of it, and the
help's example and its claim about what is read again are corrected.
A hold means nothing is dispatched or posted until it is released. The
handoff honored it and the runner did not: started under a hold, it went on
giving its orchestrator the messages it already held and starting the workers
that were waiting. It now starts no agent while the hold stands, and takes up
where it was when the hold is released.

A process a crashed run left is ended before its session is continued. When it
could not be confirmed ended, the session was continued all the same, beside
whatever was still running. The recorded group now gets the rule's last step
as well, which ends what a vanished leader left behind, and a group that still
cannot be confirmed gone keeps its record: a worker is closed as failed, which
the orchestrator is told, and an orchestrator's stops the start.

The comments said a crash between writing a request and keeping it repeats the
request. That holds only for a start within the handoff's grace: an older
record is not run late, with a runner or without. They now say so.
A start now confirms each process a crash left is gone, after the signal
as well as when the leader had already gone, and one that cannot be
confirmed stops the start whichever session it was. A worker that was
only set aside could still be told more, or take a later request on its
thread, beside the process nobody ended.

The socket's directory is checked wherever it is listened on or called:
a real directory, this user's, closed to everyone else. The fallback for
a long path sits under XDG_RUNTIME_DIR when there is one, and an agent is
given the socket's path itself rather than the directory to derive it
from.

A failed lookup of a card's On Hold section is logged, and the accept
loop only reads the run's end as the reason for an error when there was
one.
A socket that cannot sit in the runner's directory, because the path is
too long for an address, went wherever the environment of the moment
said, so a command started with another environment looked somewhere
else and reported the running connector absent. The connector now keeps
where it listens beside its state, and a call reads that.

The runtime directory is used only when the whole path fits an address.
The directory check compares the effective user, as the connector's
other ownership checks do, and off Unix it refuses rather than passing
everything.
Copilot AI balanced review requested due to automatic review settings November 11, 2026 23:49

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

Critical gaps in process persistence, shutdown confirmation, and hold rechecking can leave agents untracked, allow overlapping processes, or start work while a hold remains active.

7 open issues

Review effort: Balanced

Comment thread internal/connector/runner/runner.go Resolved
Comment thread internal/connector/runner/turn.go Resolved
Comment thread internal/connector/runner/workers.go Resolved
Comment thread internal/connector/runner/workers.go Resolved
Comment thread internal/connector/runner/workers.go Resolved
Comment thread internal/connector/runner/workers.go Resolved
…saved

A start does not begin beside a process it cannot confirm ended. A turn
is now held to the same:

- The record of a turn's process goes only once nothing of its process
  group is left. One that stays fails its worker, is asked after again
  before that session's next turn, orchestrator or worker, and is the
  next start's to end.
- An agent whose process could not be written to the state is ended
  before it is told anything, and reported as one that could not run.

A worker continued after a stop is given what it was last on along with
the notice that it was interrupted: a stop just after its turn began may
have come before its session had the request.

A dispatch to a thread's earlier worker, or a message sent to a worker,
that could not be saved leaves the worker as it was, rather than queued
with nobody to run it.
Copilot AI balanced review requested due to automatic review settings November 12, 2026 03:04

@cubic-dev-ai cubic-dev-ai Bot 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.

All reported issues were addressed across 8 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread internal/connector/runner/runner.go Resolved
Comment thread internal/connector/runner/doc.go Resolved

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.

Comment thread internal/connector/runner/store.go Resolved
Copilot AI balanced review requested due to automatic review settings November 12, 2026 03:12

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

Worker pruning can erase the only durable record of a surviving process, and startup can bypass a hold applied during a configuration wait.

2 open issues

Review effort: Balanced

Copilot AI balanced review requested due to automatic review settings November 12, 2026 03:19
@robzolkos
robzolkos merged commit 48b01aa into main Nov 12, 2026
32 checks passed
@robzolkos
robzolkos deleted the connect-runner branch November 12, 2026 03:27

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

Worker and orchestrator turns can bypass a hold established while waiting for runner.json repairs because the hold is not revalidated before launch.

1 open issue
1 resolved since last review

Review effort: Balanced

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

Labels

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants