diff --git a/src/agent-runner.ts b/src/agent-runner.ts index 3cbf0f7..5609a54 100644 --- a/src/agent-runner.ts +++ b/src/agent-runner.ts @@ -70,13 +70,9 @@ export async function runAgentProcess( envOverrides?: Record, ): Promise { // ── Reviewer container mode ───────────────────────────────────── - // When EJCLAW_REVIEWER_RUNTIME is set in envOverrides, run the reviewer - // inside a Docker container with read-only source mount instead of - // as a host process. This provides kernel-level write protection. - const isReviewerContainer = - envOverrides?.EJCLAW_REVIEWER_RUNTIME === '1' && - getEnv('REVIEWER_CONTAINER_ENABLED') !== '0'; - if (isReviewerContainer) { + // Reviewers always run inside a Docker container with read-only source + // mount for kernel-level write protection. Docker is required. + if (envOverrides?.EJCLAW_REVIEWER_RUNTIME === '1') { const ownerWorkspaceDir = envOverrides?.EJCLAW_WORK_DIR || group.workDir || process.cwd(); return runReviewerContainer({ diff --git a/src/paired-workspace-manager.ts b/src/paired-workspace-manager.ts index 5d79743..9b93c54 100644 --- a/src/paired-workspace-manager.ts +++ b/src/paired-workspace-manager.ts @@ -537,9 +537,23 @@ export function markPairedTaskReviewReady(taskId: string): { if (!ownerWorkspace) { return null; } - const reviewerWorkspace = refreshReviewerSnapshotForPairedTask(taskId); - const now = new Date().toISOString(); + // Reviewer runs in a container with the owner workspace mounted read-only. + // No file-level snapshot copy needed — just register the path. + const reviewerWorkspace = makeWorkspaceRecord({ + taskId, + role: 'reviewer', + workspaceDir: ownerWorkspace.workspace_dir, + snapshotSourceDir: ownerWorkspace.workspace_dir, + snapshotRefreshedAt: requestedAt, + }); + upsertPairedWorkspace(reviewerWorkspace); + logger.info( + { taskId, ownerDir: ownerWorkspace.workspace_dir }, + 'Reviewer will mount owner workspace directly', + ); + + const now = new Date().toISOString(); updatePairedTask(taskId, { status: 'review_ready', updated_at: now,