Skip to content

Connect ACP clients to a live REPL Sidekick - #989

Draft
taras wants to merge 6 commits into
agent/testagent-model-options-984-deliveryfrom
agent/sidekick-acp-access-961
Draft

taras wants to merge 6 commits into
agent/testagent-model-options-984-deliveryfrom
agent/sidekick-acp-access-961

Conversation

@taras

@taras taras commented Oct 24, 2026

Copy link
Copy Markdown
Owner

Why

Connect an ACP client to the Sidekick already held by a live REPL, so it can send a text request and inspect the resulting public activity and entry evidence.

This is a dependent draft on #988. Its initial head is 806dc51cde6b9ad32b63cfaeeb8f39a17fea786e; the selected parent branch is agent/testagent-model-options-984-delivery at d9c43800b491271a1ad07f9cda24caa66ea8c830.

What changes

Before: the REPL's Sidekick has no external ACP attachment or passive command-line read path.

After: start or resume a REPL with an established selected Sidekick conversation and opt in to a private attachment file. Use an existing owner-controlled parent directory:

xmd repl 'xmd://repl/<execution>/entries' --sidekick-acp /absolute/private/attachment.json

Configure an ACP client to launch this stdio backend:

xmd sidekick acp --attach /absolute/private/attachment.json

A separate command can read current public status without sending a prompt:

xmd sidekick read --attach /absolute/private/attachment.json status

Message reads can follow an acknowledged message reference; entry reads return bounded Source, Prompt, Output or Journal pages. The attachment creates no underlying conversation and keeps the selected provider and permissions.

How it works

ACP text prompt or UI Send
  -> one live REPL dispatch and admission policy
  -> existing Sidekick generation, evaluation and feedback
  -> public updates, evaluated Output and joined exchange result

passive read or exact load
  -> existing owner's public state
  -> no new prompt

The opt-in endpoint uses a same-user POSIX Unix socket and a private descriptor bound to the live owner, execution, conversation and cwd. Strict requests and bounded observer queues keep malformed or slow clients from blocking the producer.

Disconnect detaches observation while the REPL continues its exchange. Explicit ACP cancel/close captures and joins only that attachment's exchange. Busy work refuses before a message is saved. External messages retain origin and an acknowledged opaque ID without clearing the human's composer or taking over a held draft.

Review guide

Start with specs/repl-spec.md, “Attaching to the live Sidekick”.

Then review:

  1. packages/cli/src/repl/sidekick/dispatch.ts and its application integration for shared admission and producer ownership.
  2. packages/cli/src/sidekick-acp/ for descriptor identity, bridge mappings, safe reads and exact cancellation.
  3. repl-sidekick-acp.test.ts and repl-sidekick-dispatch.test.ts for the attachment and shared-dispatch regressions.

Look carefully at completed-load replay, disconnect versus cancellation, replaced-file cleanup, and a failed follow-up after an earlier answer.

What must stay true

  • One Sidekick conversation and ordinary entry admission remain authoritative. ACP adds no evaluator, journal writer or entry controller.
  • Saved-message acceptance, joined exchange completion and the evaluated product verdict are distinct. An earlier answer, preview or bare end_turn cannot establish a missing completion.
  • Passive read/load/follow sends no prompt. UI question answering and independently admitted entry ownership remain separate.
  • The host adapters own socket and filesystem resources; shared orchestration remains scoped Effection operations.

The dispatch, attachment, lifecycle, control and repository regression coverage checks these boundaries.

How to verify it

Recorded focused evidence passed on the candidate whose complete source corresponds to this exact head: the eight-file attachment/help/boundary/lifecycle/control/observation/repository/Session-configuration selection reported 39 tests, 186 steps, zero failures, with two real-child summaries of one test and six steps each.

The controlled integration exercises the released ACPX 0.12.0 CLI and XMD's distinct patched provider/runtime, including serial requests, passive reconnect/load, cancellation and incomplete-result controls. The first selection exposed an A6 fixture teardown failure; the correction drains the real event iterator before closing the runtime. The first failure remains retained. A temporary-file collision is a scheduling inference, not an instrumented interleaving.

Both original independent source reviewers passed this exact head. One committed deno task verify:clean passed on it; that proves dependency ownership and non-interference, separately from product correctness.

These are recorded local results on Darwin arm64/Deno 2.9.7, not final CI results or a live operator Sidekick recovery trial. No tests were rerun to prepare this description.

Scope

Included: shared Sidekick dispatch, opt-in local ACP text/load/close support, passive status/message/entry reads, runtime adapter installation, and the associated help, specifications and regressions.

Deferred scope includes queueing, coediting, cross-client question answers, live relationship recovery, remote hosting and repository-wide ACP. The current --observe-worktree spelling remains unchanged; its separate naming proposal has no human approval.

Refs #961, #963.

New abstractions and dependencies

The private dispatch handle serves UI Send and ACP while keeping the producer under the REPL root. The private transport supports the ACP bridge and passive CLI reader without exposing the execution controller.

The CLI declares its direct @agentclientprotocol/sdk@1.3.0 import for the stdio bridge, using the already selected SDK version. deno.lock records that real dependency edge. ACPX and vendor bytes are unchanged; no generated browser or vendor output is added.

Risks and remaining delivery gates

This remains a draft. Combined-source runner measurement and authentic artifact/weight integration are pending delivery work; this description claims no run ID, outcome or consumed artifact. Existing d9 measurements and CI retain their own commit provenance.

Required CI must prove the actual final published head and current main. Any resulting weight or integration commit needs affected evidence correspondence and both original final-head reviews. Final Planner metadata APPLY and independent VERIFY remain outstanding after the configured CI and artifact gates.

The endpoint is POSIX-only and requires an established selected conversation. Switching conversations invalidates the attachment. Controlled client evidence does not resolve the held live Sidekick's unknown feedback acceptance.

Scope confirmation

  • Every changed file supports the purpose described above.
  • Unrelated cleanup and formatting changes are excluded.
  • The lock change and absence of generated output are identified.
  • Final delivery results and metadata are verified on the final head.

@github-actions

Copy link
Copy Markdown

PR #989: Connect ACP clients to a live REPL Sidekick

29 files, +3590 / -188

Scope

🔴 PR has 3778 lines changed. Split into focused PRs.

🟡 3778 lines changed. PRs under 400 receive more thorough review.

🟡 29 files changed. Are all changes related?

🟡 PR mixes config and source changes.

Structural

🟡 3 console statements.

Oxlint structural signals:

  • no-unused-vars ×24: packages/cli/tests/fixtures/repl/issue-883/sidekick-harness.ts, packages/cli/src/repl/application.ts, packages/cli/src/repl/program.ts (+1)
  • no-redundant-type-constituents ×7: packages/cli/src/sidekick-acp/posix.ts
  • no-empty-function ×5: packages/cli/src/sidekick-acp/posix.ts, packages/cli/src/sidekick-acp/bridge.ts, packages/cli/src/cli.ts
  • no-unnecessary-type-arguments ×5: packages/cli/src/repl/sidekick/dispatch.ts, packages/cli/src/sidekick-acp/posix.ts, packages/cli/src/sidekick-acp/server.ts (+1)
  • no-unnecessary-type-assertion ×1: packages/cli/tests/fixtures/repl/issue-883/sidekick-harness.ts
  • no-unnecessary-boolean-literal-compare ×1: packages/cli/src/repl/application.ts

Slop

Oxlint slop signals:

  • no-console ×6: packages/cli/src/sidekick-acp/command.ts, packages/cli/src/cli.ts

Static Analysis

Oxlint: 178 diagnostics across 13 files (20 rules)
Density: 0.050 violations/added-line

no-shadow (71): packages/cli/src/repl/sidekick/history.ts, packages/cli/src/repl/sidekick/dispatch.ts, packages/cli/src/repl/sidekick/model.ts (+5)
no-unused-vars (24): packages/cli/tests/fixtures/repl/issue-883/sidekick-harness.ts, packages/cli/src/repl/application.ts, packages/cli/src/repl/program.ts (+1)
no-floating-promises (18): packages/cli/src/repl/sidekick/dispatch.ts, packages/cli/src/repl/program.ts, packages/cli/src/sidekick-acp/posix.ts (+2)
no-redundant-type-constituents (7): packages/cli/src/sidekick-acp/posix.ts
consistent-return (7): packages/cli/src/repl/program.ts, packages/cli/src/repl/application.ts, packages/cli/src/cli.ts
no-console (6): packages/cli/src/sidekick-acp/command.ts, packages/cli/src/cli.ts
no-underscore-dangle (6): packages/cli/src/sidekick-acp/bridge.ts
unbound-method (6): packages/cli/src/repl/program.ts, packages/cli/tests/fixtures/repl/issue-883/sidekick-harness.ts, packages/cli/src/cli.ts
no-empty-function (5): packages/cli/src/sidekick-acp/posix.ts, packages/cli/src/sidekick-acp/bridge.ts, packages/cli/src/cli.ts
no-unnecessary-type-arguments (5): packages/cli/src/repl/sidekick/dispatch.ts, packages/cli/src/sidekick-acp/posix.ts, packages/cli/src/sidekick-acp/server.ts (+1)
no-array-sort (4): packages/cli/src/repl/sidekick/model.ts, packages/cli/src/repl/application.ts
no-unsafe-type-assertion (4): packages/cli/src/deno.ts, packages/cli/tests/fixtures/repl/issue-883/sidekick-harness.ts, packages/cli/src/cli.ts
consistent-function-scoping (3): packages/cli/src/repl/application.ts
no-useless-default-assignment (3): packages/cli/src/repl/program.ts, packages/cli/src/repl/application.ts
no-duplicate-type-constituents (3): packages/cli/src/repl/application.ts
no-useless-spread (2): packages/cli/src/repl/sidekick/dispatch.ts, packages/cli/src/cli.ts
no-unmodified-loop-condition (1): packages/cli/src/cli.ts
no-unnecessary-type-assertion (1): packages/cli/tests/fixtures/repl/issue-883/sidekick-harness.ts
no-misused-spread (1): packages/cli/src/repl/application.ts
no-unnecessary-boolean-literal-compare (1): packages/cli/src/repl/application.ts

Correctness

No extraneous code patterns detected.

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

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant