Skip to content

Run Ask in the lane D agent container - #54

Merged
mchwang merged 46 commits into
mainfrom
ask-in-container
Sep 27, 2026
Merged

mchwang merged 46 commits into
mainfrom
ask-in-container

Conversation

@mchwang

@mchwang mchwang commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor

Closes #64. Lane F item: move Ask onto lane D's invocation contract. This ends the interim R1 exception that #52 recorded. Base: main (retargeted after #52 merged).

Summary

Ask no longer runs the claude or codex CLI on the host. It runs in lane D's container, in the read-only questions phase.

Before After
Where the agent runs Host process, temporary folder, your environment Lane D container: read-only root, no capabilities, bounded storage
Code it can see Only the context in the prompt That context, plus a read-only clone of the reviewed snapshot head at /work
Commands Turned off by CLI flags questions phase: read, list and search only, enforced by lane D's policy
Network Host network Vendor-only proxy
Sign-in Host CLI login or keychain CLAUDE_CODE_OAUTH_TOKEN (from claude setup-token) or Codex auth.json, never stored

How it works

  • runner/question-container.ts builds the image once per worker and clones the reviewed head. It allocates storage and captures the invocation (no approved argv), then starts the adapter. Storage is removed only after settled.
  • runner/question-worker.ts: lane D's entry points are synchronous (Docker and Git calls), so one worker thread owns them and the review server stays responsive.
  • runner/question-agent.ts (QuestionWorker) settles a question only when the worker reports that its container and storage are gone.
  • There is no host fallback. A missing token, missing auth.json or missing Docker fails with a message that names what is missing.

Fail-closed ownership stopgaps (added during review). Lane D does not yet label resources with their owner, bound its clone, or recover leftovers after a restart (#51 items 1, 3 and 4). Until it does, Ask owns and records its own leftovers in runner/question-leftovers.ts, next to the review database:

  • Result identity: the invocation reuses the persisted answer attempt, and referencedCodeHash is the note's contextId. Results with another attempt or context, a missing exit code or any signal are rejected.
  • Durable cleanup:
    • Storage whose removal Docker did not confirm is retained and retried, then recorded at shutdown.
    • Each worker gets one Ask root (<tmp>/codeboost-ask-*), used as its TMPDIR and recorded before the worker starts. It holds the clone, lane D's input and the Codex auth copy. Each root carries an owner stamp, so it can be found without the record.
    • A crash, a missing release report, or a question that does not settle 30 s after its deadline abandons the worker once. Waiters are released only after the thread stops (bounded), and unknown leftovers are recorded.
  • Admission:
    • The first question of each process scans Docker for every lane D label (io.codeboost.allocation, io.codeboost.invocation, io.codeboost.egress). The scan runs single-flight.
    • Ask stays off while recorded or unidentified leftovers remain, and the error names removal commands.
    • Shutdown stops question admission in the same turn as the server's stopping flag.
  • Exclusion: one process per review database, via an exclusive SQLite (OS) lock keyed by the database file's device and inode. The record is keyed by the canonical path. Hard-linked databases are refused.
  • Isolation:
    • The worker's environment is an allowlist (PATH, DOCKER_HOST, TMPDIR); credentials reach it as workerData.
    • The Git size check before cloning uses lane D's hardened invocation and refuses repositories larger than the 512 MiB allocation.
    • Record entries and owner stamps are validated by exact location, and the record is written through an exclusive random temporary file.

Behavior changes for users

  • Ask, including npm run demo, needs Docker plus a token or auth.json. The first question builds the agent image. If that exceeds the two-minute question deadline, the question fails, and a retry reuses the finished layers.
  • A repository larger than the 512 MiB storage allocation is refused before anything is copied.
  • After a crash or kill, Ask may stay off until labelled leftovers are removed. The error message gives the commands.

Scope decision for the reviewer

About 400 lines of the stopgaps above exist only because lane D lacks owner labels, a bounded clone and scoped recovery (#51). The per-review lock overlaps with F1d's single-runner lock (#59). The options are: merge now and replace these parts when #51 and F1d land (tracked in #65), or hold this PR for #51.

Ownership and coordination

Validation

Validated head: 64ac028 (current main merged in at 63a11cf).

  • npm run typecheck: passed.
  • Unit tests with CI's excludes: 486/486 passed (18 files).
  • npm run test:browser: 58/58 passed (on 88bb96f; later commits touch only Ask's leftover module, its tests and docs).
  • CI (test, real-docker) on 64ac028 is the final exact-head check; on the earlier head 6f047ac both passed.
  • test/agent-question.test.ts (real Docker) ran in CI's real-docker job. The live Claude case has not run; it needs a real CLAUDE_CODE_OAUTH_TOKEN and CODEBOOST_RUN_AUTH_PROBES=1.
  • Each review fix has a regression test. For each, I broke the fix on purpose and confirmed the test failed before restoring it.

Review rounds

About 20 Copilot rounds produced 60 inline findings. All 60 threads are resolved; the reply in each thread cites the fixing commit and its regression test. Rounds that reviewed an older head re-reported findings that were already fixed; those threads cite the earlier fix. As AGENTS.md requires, summary-only concerns without a location were reproduced where possible, or filed as follow-ups: #64 (stop reason passed as message text; Copilot later pinpointed it, and this PR now fixes and closes it) and #65 (shared-daemon isolation; open, depends on #51 item 3). One finding did not reproduce (startup marker, 4112551858). A regression for the reported case is included.

Review-lesson audit

Every finding is classified below. Rule citations refer to AGENTS.md in this head.

Covered by existing rules

  • "Never apply a background response without proving it is still current": result identity and context (4110696969).
  • "Validate coupled lifecycle fields as allowed combinations": null exit code or signal accepted as success (4110993674).
  • "Do not release a concurrency slot when cancellation is requested…" and "A deadline must abort and await the underlying operation before releasing its in-flight ownership": abandon before termination, the timer race, concurrent abandon, close during abandon, failed terminate treated as stopped (4112271725, 4112295157, 4112361784, 4112456414, 4112728747).
  • "Bound the HTTP drain during shutdown…" and "Track an in-flight irreversible subprocess as part of server shutdown…": unbounded D settlement, shutdown deadlock, unbounded release-timeout terminate, scan outliving close(), Docker children outliving an abandoned thread (the lock is now kept until process exit), pending questions released when the termination wait expires (answered: the durable handoff is in place; no code change) (4112245838, 4112245880, 4112311246, 4112484482, 4113923388, 4113971096).
  • "Begin shutdown by rejecting new work … then cancel and await jobs, then close storage": a failed Ask cleanup skipped closing the store (4113923423).
  • "Begin shutdown by rejecting new work at the outer admission boundary" and "Set the shutdown admission flag before snapshotting active work…": admission after shutdown began (4112645321).
  • "Batch and briefly cache read-only status probes, and give the combined operation an overall deadline": unbounded per-resource cleanup gate (4112207416).
  • "A bounded safety scan must fail closed when its limit is exceeded. Never truncate evidence": record truncation, root overflow (4112207449, 4112376096).
  • "When startup acquires … resource before later dependency construction, close that resource on every construction failure": worker construction failure (4112376078).

Captured by new rules in this head (AGENTS.md, "Owned host and Docker resources")

  • Durable cleanup ownership: worker crash, lost removal handles, shutdown discarding retained storage, crash treated as clean release, setup failure without a handle, abandoned staging paths, the Codex auth copy, missing record at startup, failed final record write, lock kept after failed write, rename losing the record, unnamed labelled resources, the seeder missed by labels (4110696991, 4110697011, 4112180878, 4112180891, 4112207386, 4112207433, 4112219113, 4112245818, 4112245859, 4112282859, 4112282891, 4112376104, 4112519512, 4112645299, 4112708625).
  • Allowlisted environments and hardened Git: credential leakage to setup subprocesses, the heuristic scrub, an unhardened Git size check (4112271713, 4112334205, 4112334222, 4112551830).
  • Untrusted paths and exclusive writes (extended in this head to forbid following links and to require a private directory for plantable files): basename-only path validation, an untrusted owner stamp opened as a file, a predictable temporary file, a symlinked lock file in the shared temp directory, deleting unauthenticated lookalike folders, a linked owner stamp, a linked record file (4112282910, 4112551842, 4112609105, 4113923407, 4113933100, 4113971119, 4113971130).
  • Cross-process OS locks and single-flight startup: no admission lock, unserialized record writes, reclaiming a live root, PID reuse, stale-lock takeover race, a path-keyed lock, a lock not surviving a rename, the double startup scan (4112311217, 4112311270, 4112323715, 4112345944, 4112345961, 4112361825, 4112484508, 4112432968).

Summary-only findings with a location (no inline thread)

One-off (recorded why)

  • 4110993691, referencedCodeHash hashed the prompt: a wrong field choice, specific to this contract.
  • 4112168277, workflow path filter missed runner/questions.ts: a file-naming slip.
  • 4112207464, && in the displayed removal command: a message-formatting bug.
  • 4112271730, credential check ran after the Docker scan: step ordering in one entry point.
  • 4112361805, unbounded host clone: a lane D API gap. The size check before cloning is a stopgap until D provides a bounded clone (D follow-ups required by the F1 runner lifecycle contract #51).
  • 4112551858: did not reproduce; a regression for the reported case is included.
  • 4113992060, worker started with the full environment: did not reproduce. workerEnvironment() allowlists PATH, DOCKER_HOST and TMPDIR, and the existing integration test covers it. The suggested this.env is the credential source and would leak the token.

🤖 Generated with Claude Code

mchwang and others added 3 commits September 26, 2026 00:43
Record where the code differs from the approved plan and update stale status:

- Record Ask as an interim exception to R1: it runs the vendor CLI on the
  host with tools off until lane F moves it into the lane D container.
- Amend D20: there is no "Merge anyway"; to override a blocker, merge on
  GitHub. Matches docs/implementation/guarded-merge.md.
- Tick T1, T2, T4, T5, T10, T13, T14 with test evidence; point Files lines
  at core/linking.ts and core/approvals.ts instead of never-created modules.
- Mark increment 1 merged; add a lane status table (C, D, K done; E, F, H
  progress); record decided open questions (issue ranking, AgentDiff).
- Add a verified status note for design tasks DT2-DT15; none newly ticked.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The guarded merge gate doc still said merge-queue branches stay blocked.
#46 (closing #24) added queue lifecycle support. Point to merge-queue.md,
and state that adapters without queue inspection still fail closed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ask used to run the claude/codex CLI on the host with each CLI's own
restrictions, an interim exception to R1. It now uses lane D's invocation
boundary in the read-only "questions" phase: a clone of the reviewed
snapshot head at /work, no commands, vendor-only network, and no other
host files. There is no host fallback.

- runner/question-container.ts: build image, clone, allocate bounded
  storage, capture, start the Claude/Codex adapter; release storage only
  after the invocation settles. Deps are injectable for unit tests.
- runner/question-worker.ts: lane D setup is synchronous, so a worker
  thread owns it and the review server stays responsive.
- runner/question-agent.ts: QuestionWorker bridge; a question settles only
  when the worker reports the container and storage are gone.
- Credentials come from the environment only: CLAUDE_CODE_OAUTH_TOKEN for
  Claude, CODEBOOST_CODEX_AUTH_FILE or CODEX_HOME/auth.json for Codex.
- Provider failures include the vendor's short message (e.g. a 401).
- test/agent-question.test.ts runs the path on real Docker (Agent
  isolation workflow); its live case needs the auth-probe credentials.
- Plan, README, Settings copy and implementation docs updated; the R1
  exception is closed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings September 26, 2026 08:20

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Critical and moderate findings remain around invocation integrity, cleanup recovery, worker crashes, and CI coverage.

Review effort: Lite
Findings: 1 High severity · 2 Medium severity

Open (3)
What changed in this PR

Moves Ask from host CLI execution into lane D’s isolated Docker container workflow.

Changes:

  • Adds worker-thread orchestration and container-backed Claude/Codex execution.
  • Adds credential, storage, cancellation, cleanup, and Docker integration tests.
  • Updates UI, CLI guidance, documentation, and CI workflows.

Unresolved findings concern invocation identity/context, resource cleanup and crash recovery, and workflow path coverage.

File Summary
web/​public/​app.js Updated settings guidance
web/​cli.ts Updated CLI guidance
test/​questions.test.ts Question lifecycle coverage
test/​question-agent.test.ts Orchestration and worker tests
test/​fixtures/​question-worker-stub.ts Worker test fixture
test/​agent-question.test.ts Real Docker integration tests
runner/​questions.ts Ask orchestration and scope
runner/​question-worker.ts Lane D worker bridge
runner/​question-container.ts Container lifecycle and cleanup
runner/​question-agent.ts Worker lifecycle and cancellation
README.md Containerized Ask documentation
docs/​implementation/​read-only-review.md Superseded host-adapter documentation
docs/​implementation/​agent-isolation.md Ask isolation documentation
docs/​designs/​codeboost-plan-indexed-review.md Updated roadmap and safety status
.github/​workflows/​ci.yml Excludes Docker tests from main CI
.github/​workflows/​agent-isolation.yml Runs Ask isolation tests

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

Comment thread runner/question-container.ts Outdated
Comment thread runner/question-agent.ts Outdated
Comment thread runner/question-container.ts
mchwang and others added 3 commits September 26, 2026 02:37
Merge main. Record the F1 lifecycle contract (#49) and open F1a-F1c
(#53, #56, #57); record the ranked Issues screen (H4a, #55) with H4b's
trust action remaining; Issues is now a menu link, not a placeholder.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nto ask-in-container

# Conflicts:
#	docs/designs/codeboost-plan-indexed-review.md
Copilot AI review requested due to automatic review settings September 26, 2026 09:44

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Unresolved lifecycle, cleanup, cancellation, identity, permissions, result-validation, and CI coverage findings remain.

Review effort: Lite
Findings: 2 High severity · 3 Medium severity

Open (5)

Comment thread runner/question-container.ts
Comment thread runner/question-container.ts Outdated
mchwang and others added 3 commits September 26, 2026 03:46
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
README no longer says merge queues block merging; it describes the
enqueue-then-confirm behaviour. The plan's wave-3 note records the old
block as history instead of a live instruction.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nto HEAD

# Conflicts:
#	docs/designs/codeboost-plan-indexed-review.md
Copilot AI review requested due to automatic review settings September 26, 2026 17:16

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🔵 Needs a closer look

Four moderate findings remain around cancellation, crash recovery, cleanup recovery, and stderr diagnostics.

Review effort: Lite
Findings: 2 High severity · 3 Medium severity

Open (5)

mchwang and others added 3 commits September 26, 2026 10:21
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The plan (R1 exception) says README states this limit; it did not.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings September 26, 2026 17:31

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Moderate resource-lifecycle, worker, container, and workflow coverage issues remain unresolved.

Review effort: Lite
Findings: 2 High severity · 4 Medium severity

Open (6)

Comment thread .github/workflows/agent-isolation.yml
- Reuse the persisted answer attempt as the invocation attempt, and the
  note's contextId as referencedCodeHash. Accept a result only when its
  attempt and context match the captured invocation and the worker reply
  carries the same attempt.
- Treat a missing exit code or any signal as a failure, not an answer.
- Keep task storage whose removal Docker did not confirm, retry removal
  before the next question, and refuse Ask while any remains.
- After a worker crash, fail closed instead of starting a replacement:
  its containers and storage may still exist, and reclaiming them needs
  lane D's scoped recovery (#51 item 4).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings September 26, 2026 17:35
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
After a failed release-report write the worker thread has stopped and
the root is already recorded, so let go of the root in this process:
it stays on disk and in the record for the next check, and close() can
release the per-review lock instead of holding it for the process.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings September 26, 2026 20:42

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Unresolved lifecycle, cancellation, resource-ownership, and shutdown error-handling issues remain.

Review effort: Lite
Findings: 1 High severity

Open (1)
Resolved since last review (1)

Comment thread runner/question-agent.ts Outdated
A rejected terminate() no longer counts as a stopped thread: the Ask
root stays on disk and in the record, and the lock stays held, instead
of being removed while the worker may still be alive. Later cleanup runs
only after a termination that actually settled.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings September 26, 2026 20:52

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🔵 Needs a closer look

Two unresolved moderate issues remain in cancellation handling and shared Docker-resource isolation.

Review effort: Lite
Findings: None

Resolved since last review (1)

Resolves README and plan conflicts: keeps this branch's text wherever
main still describes Ask as a host-CLI exception, and takes main's
merge-queue retry wording and planned-vs-current install requirements.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings September 27, 2026 03:07
@mchwang
mchwang changed the base branch from docs/reconcile-plan-with-code to main September 27, 2026 03:07
Four rules for owned host and Docker resources: durable cleanup
ownership, allowlisted subprocess environments and credential channels,
untrusted record and on-disk paths, and cross-process OS locks keyed by
stable identity.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Unresolved critical and moderate lifecycle, cleanup, locking, and timeout issues remain.

Review effort: Lite
Findings: 3 High severity

Open (3)

Comment thread runner/question-agent.ts
Comment thread runner/question-leftovers.ts Outdated
Comment thread runner/questions.ts
Copilot AI review requested due to automatic review settings September 27, 2026 03:12

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Six unresolved findings remain, including one critical cleanup issue.

Review effort: Lite
Findings: 4 High severity

Open (4)
Previously missed (2)

In code that hasn't changed since last review

Medium severity Transport typed stop reasons instead of inferring them from messages

runner/​question-container.ts:209

The D StopReason is reconstructed from user-facing error-message text (and the worker bridge transports only that text). A wording change, or an unrelated message containing timed out or Server stopped, can turn a timeout into shutdown/cancellation or vice versa, losing the lifecycle reason required by the invocation contract. Carry a typed reason separately from the display message through the worker boundary.

Medium severity Lane-D resource scan is not scoped to this review

runner/​question-leftovers.ts:293

This scan treats every resource with a lane-D label as belonging to this review and marks any unlisted resource as a blocker. Since the current labels have no runner identity, a different codeboost review sharing the Docker daemon makes this review refuse all Ask until the other review's resources disappear. Scope the scan by a runner-owner label/recovery API before removing this stopgap, or keep the feature gated on that prerequisite.

Comment thread runner/question-leftovers.ts Outdated
… abandon

- web/server.ts closes the review store in a finally block when Ask's
  cleanup fails, and the CLI exits non-zero instead of hanging.
- Ask lock files live in a private per-user directory under the temp
  directory (mode 0700, checked ownership); a lock path that is a
  symlink or not a plain file is refused, never opened.
- After any abandonment the review lock is kept until the process
  exits: Docker CLI children the terminated thread started can outlive
  it and cannot be awaited until lane D exposes process groups (#51).
- AGENTS.md: the untrusted-path rule also forbids following links and
  requires a private directory for plantable files.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings September 27, 2026 03:23

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🔵 Needs a closer look

Unresolved stop-reason propagation and cleanup issues remain, along with outdated documentation.

Review effort: Lite
Findings: 1 High severity

Open (1)
Resolved since last review (3)
Previously missed (1)

In code that hasn't changed since last review

Medium severity Pass typed lane-D stop reason to cancellation handler

runner/​question-container.ts:209

The lane-D StopReason is still reconstructed from user-facing error wording here. Any wording change, localization, or non-Error abort reason silently maps timeout/shutdown to cancelled, so the adapter and persisted answer lose the original lifecycle reason. Carry a typed reason through the worker request and pass it directly to handle.cancel(); keep the message only for display.

mchwang and others added 2 commits September 26, 2026 20:31
…alone

- Closes #64: the stop reason (timeout, shutdown, cancelled) now travels
  as a StopError value from Questions through the worker message to
  handle.cancel(), instead of being rebuilt from message wording.
- The orphan-root scan deletes only folders this user owns that carry a
  valid createAskRoot stamp naming a lock in the private lock directory
  whose owner is gone; unstamped, tampered or foreign folders stay.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Unresolved critical and moderate lifecycle, cleanup, and symlink-safety findings remain.

Review effort: Lite
Findings: 3 High severity

Open (3)
Resolved since last review (1)

Comment thread runner/question-agent.ts
Comment thread runner/question-leftovers.ts
Comment thread runner/question-leftovers.ts

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🔵 Needs a closer look

Unresolved lifecycle and isolation findings remain in a broad resource-management change requiring human review.

Review effort: Lite
Findings: 3 High severity

Open (3)

The leftover record and each folder's .owner stamp are now read through
O_NOFOLLOW and accepted only as regular, single-link files within a size
limit. A linked record makes the ledger unreadable (Ask fails closed and
never acts on the record it points to); a linked stamp leaves the folder
alone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Unresolved environment-isolation and resource-cleanup findings remain, including one critical finding.

Review effort: Lite
Findings: 1 High severity

Open (1)
Resolved since last review (3)

Comment thread runner/question-agent.ts
@mchwang

mchwang commented Sep 27, 2026

Copy link
Copy Markdown
Contributor Author

Follow-ups from Copilot's summary-only review concerns (no inline thread):

🤖 Generated with Claude Code

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.

Ask: pass the stop reason as a typed value across the worker boundary

2 participants