Skip to content

feat(core): ExecutionContext abstraction for task isolation (#532) - #536

Merged
frankbria merged 2 commits into
mainfrom
feature/issue-532-execution-context-abstraction
Apr 3, 2026
Merged

feat(core): ExecutionContext abstraction for task isolation (#532)#536
frankbria merged 2 commits into
mainfrom
feature/issue-532-execution-context-abstraction

Conversation

@frankbria

@frankbria frankbria commented Apr 3, 2026

Copy link
Copy Markdown
Owner

Summary

  • Adds IsolationLevel enum and ExecutionContext dataclass in new codeframe/core/sandbox/ package
  • --isolation none|worktree|cloud flag on cf work start and cf work batch run
  • conductor.py creates context before each task dispatch, calls cleanup() in finally block
  • runtime.execute_agent() creates context, passes effective_repo_path to adapters
  • Uses existing TaskWorktree from worktrees.py for WORKTREE isolation (reuses tested git logic)
  • 16 new tests covering full context lifecycle

Test plan

  • tests/core/test_sandbox_context.py — 16 tests: IsolationLevel enum, ExecutionContext dataclass, NONE no-op, WORKTREE create/cleanup with real git repo, CLOUD raises NotImplementedError
  • tests/core/test_conductor.py — 63 existing tests pass (BatchRun backward compat verified)
  • uv run ruff check — all clean
  • cf work start --help and cf work batch run --help show --isolation flag

Closes #532

Summary by CodeRabbit

  • New Features
    • Added --isolation flag to work start and work batch run with modes: none (default), worktree (per-task isolated worktree), and cloud (placeholder for future cloud isolation).
  • Bug Fixes
    • Ensures per-task isolation workspaces are always cleaned up after execution.
  • Tests
    • Added tests covering isolation modes, worktree behavior, and cleanup.

Adds IsolationLevel enum and ExecutionContext dataclass in a new
codeframe/core/sandbox/ package, enabling agents to run in isolated
git worktrees instead of the shared filesystem.

- New codeframe/core/sandbox/context.py with IsolationLevel (none|worktree|cloud),
  ExecutionContext dataclass, and create_execution_context() factory
- Uses existing TaskWorktree (worktrees.py) for WORKTREE isolation
- --isolation flag wired into cf work start and cf work batch run
- conductor.py creates context before each task dispatch, cleans up after
- runtime.execute_agent() creates context, passes effective_repo_path to adapter
- BatchRun.isolation: str = "none" field with DB schema migration
- 16 tests covering context lifecycle, NONE no-op, WORKTREE create/cleanup, CLOUD NotImplementedError
- Default none preserves all existing behavior
@coderabbitai

coderabbitai Bot commented Apr 3, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a796d08b-ed19-40f3-a6c1-08e13c2df1b7

📥 Commits

Reviewing files that changed from the base of the PR and between 01acead and e1a95c6.

📒 Files selected for processing (1)
  • tests/core/test_sandbox_context.py
✅ Files skipped from review due to trivial changes (1)
  • tests/core/test_sandbox_context.py

Walkthrough

Introduces an ExecutionContext abstraction and an --isolation CLI flag (none|worktree|cloud, default none) on work start and work batch run, wires isolation through runtime.execute_agent and conductor.start_batch, implements per-task worktree handling, and adds tests for the sandbox context.

Changes

Cohort / File(s) Summary
CLI isolation flag
codeframe/cli/app.py
Added --isolation option (default "none") to work start and work batch run, validated values (none, worktree, cloud), and forwarded the flag to runtime/conductor calls.
Sandbox public API
codeframe/core/sandbox/__init__.py
Re-exported sandbox types: ExecutionContext, IsolationLevel, create_execution_context.
Sandbox implementation
codeframe/core/sandbox/context.py
New IsolationLevel enum and ExecutionContext dataclass; create_execution_context() factory supporting none (repo path, no-op cleanup), worktree (create per-task worktree, provide cleanup), and cloud (raises NotImplementedError).
Runtime integration
codeframe/core/runtime.py
Added isolation parameter to execute_agent(); create ExecutionContext, route adapter runs via exec_ctx.workspace_path, and ensure exec_ctx.cleanup() in a finally block.
Conductor integration & persistence
codeframe/core/conductor.py
Added isolation to BatchRun and start_batch(); create ExecutionContext for task execution across serial/parallel/retry flows; pass worktree_path when different; ensure cleanup in finally; DB migration/serialization for new isolation column.
Tests
tests/core/test_sandbox_context.py
New tests verifying IsolationLevel values/roundtrip, ExecutionContext fields and cleanup behavior, create_execution_context() for none, worktree (real git repo/worktree creation and cleanup), and cloud raising NotImplementedError.

Sequence Diagram

sequenceDiagram
    participant User as User
    participant CLI as CLI (app.py)
    participant Runtime as Runtime (execute_agent)
    participant Sandbox as Sandbox (create_execution_context)
    participant Adapter as Adapter (agent)
    participant Cleanup as Cleanup

    User->>CLI: cf work start --isolation worktree
    CLI->>Runtime: execute_agent(isolation="worktree", run)
    Runtime->>Sandbox: create_execution_context(run.task_id, WORKTREE, repo_path)
    Sandbox-->>Runtime: ExecutionContext(workspace_path=worktree_path, cleanup)
    Runtime->>Adapter: adapter.run(workspace_path=worktree_path)
    Adapter-->>Runtime: result
    Runtime->>Cleanup: exec_ctx.cleanup()
    Cleanup-->>Runtime: cleanup complete
    Runtime-->>User: agent state/result
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 In burrows tidy and neat I hide,
Tasks hop into worktrees side by side,
Each one a patch, a private nest,
I clean the thickets when they rest,
Hooray for sandboxed work—what a ride! 🥕✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 46.88% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the main feature addition: ExecutionContext abstraction for task isolation, matching the core changes in the changeset.
Linked Issues check ✅ Passed All acceptance criteria from issue #532 are met: ExecutionContext and IsolationLevel defined, --isolation flag added to CLI commands, conductor creates/cleans up context, tests cover lifecycle, default behavior preserved.
Out of Scope Changes check ✅ Passed All changes align with the objectives: sandbox abstraction, CLI flag integration, conductor task dispatch updates, runtime adapter integration, and comprehensive test coverage for context lifecycle.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/issue-532-execution-context-abstraction

Comment @coderabbitai help to get the list of available commands and usage tips.

@claude

claude Bot commented Apr 3, 2026

Copy link
Copy Markdown

Review: ExecutionContext abstraction (#532)

The abstraction design is clean and well-structured. IsolationLevel as a str, Enum serializes cleanly to/from the DB, the ExecutionContext dataclass is minimal and correct, and the try/finally cleanup pattern is consistently applied across all 5 execution paths in conductor.py. Real git repo tests (no mocking) are the right call here.

A few issues worth addressing before merge:


Critical: WORKTREE isolation in batch runs likely broken

The _execute_task_subprocess worktree integration has a gap. The function correctly sets:

cwd=str(worktree_path) if worktree_path else workspace.repo_path,

But the subprocess runs cf work start, which resolves the workspace via path = workspace_path or Path.cwd(). When cwd=worktree_path, Path.cwd() points to the worktree directory — which doesn't have a .codeframe/ config directory. get_workspace(worktree_path) would fail or fall back to the wrong workspace.

The --isolation flag also isn't forwarded to the subprocess command array — only cwd changes, not what the agent inside the subprocess is told to use. For batch execution, the worktree is created and cleaned up, but the subprocess agent still loads workspace.repo_path from the DB and operates on the original repo. The single-task path (runtime.py) works correctly because it passes effective_repo_path directly to the adapter — the subprocess path needs the same treatment (pass --isolation and --workspace-path through the command).


Inline imports repeated 4x in conductor.py

from codeframe.core.sandbox.context import IsolationLevel, create_execution_context appears inside _execute_serial_resume, _execute_retries, _execute_serial, and execute_task. Should be moved to module-level imports at the top of the file.


Bare except Exception: pass in DB migration

The migration code in _save_batch swallows all exceptions, not just the "duplicate column" case. A disk full error, corrupted DB, or lock timeout would be silently ignored. Preferred:

except Exception as e:
    if "duplicate column" not in str(e).lower():
        raise

Minor: redundant path comparison repeated 5x

exec_ctx.workspace_path if exec_ctx.workspace_path != workspace.repo_path else None appears across all 5 call sites. An effective_worktree_path property on ExecutionContext (returns None for NONE, workspace_path for WORKTREE) would consolidate this. Low priority — works as-is.


Test coverage gap

No test covers the batch subprocess path with --isolation worktree. The test_sandbox_context.py tests the context object in isolation correctly, but the integration between conductor.py and subprocess worktree propagation is untested. This is where the gap above would surface.


Summary: The single-task path (runtime.py) is solid. The batch subprocess path has a real functional gap where the worktree is lifecycle-managed correctly but the subprocess agent doesn't actually use it. The other items are lower severity.

@coderabbitai coderabbitai 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.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
codeframe/cli/app.py (1)

3490-3566: ⚠️ Potential issue | 🟡 Minor

work batch run still needs the required --verbose/-v flag.

This command exposes --engine and now --isolation, but it still has no supported way to request detailed output for batch executions from the CLI surface itself.

As per coding guidelines, "All CLI commands must support the --engine flag for engine selection (default: react, legacy option: plan) and --verbose / -v flag for detailed output."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@codeframe/cli/app.py` around lines 3490 - 3566, The batch_run command handler
lacks the required verbose flag; update the batch_run function signature to add
a verbose: bool parameter exposed as a Typer/Click Option (flags --verbose and
-v, default False, help="Enable detailed output") and thread that flag into
whatever logging/execution path currently uses engine/isolation (e.g., pass
verbose into the batch executor or set process/log level where engine or
isolation are used). Ensure the new option name is consistent with existing
options and does not conflict with engine or isolation parameters.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@codeframe/core/conductor.py`:
- Around line 557-559: Validate the isolation parameter before persisting the
batch: in the function that takes isolate: bool and isolation: str -> BatchRun,
check that isolation is one of the allowed values (e.g., "none", "host",
"container", "vm" or your project's canonical set) and raise a clear validation
error if not, before calling create_execution_context(...) or saving/moving the
batch to RUNNING; apply the same preflight check for the similar block around
create_execution_context usage at the other location referenced (the code
between the earlier create_execution_context call and the block at 598-615) so
no batch is persisted when isolation is invalid.
- Around line 2146-2149: The SELECTs that populate rows for _row_to_batch() are
missing the isolation column so loaded batches default to "none"; update
get_batch() and list_batches() (and any other queries that fetch batch_runs rows
used by _row_to_batch(), e.g., resume_batch related queries) to include the
isolation column in the SELECT list in the same order as the INSERT (id,
workspace_id, task_ids, status, strategy, max_parallel, on_failure, started_at,
completed_at, results, engine, isolation) so _row_to_batch() reads isolation
from row[11] correctly.
- Around line 1020-1030: The worktree created by create_execution_context
(ExecutionContext / exec_ctx) is torn down in the finally block via
exec_ctx.cleanup() without harvesting changes, so any edits under
exec_ctx.workspace_path are deleted; before calling exec_ctx.cleanup() (after
_execute_task_subprocess returns success or result_status is available) detect
when exec_ctx.workspace_path != workspace.repo_path and persist the worktree
edits back into the main workspace (e.g., by merging/patching/copying changed
files or invoking a commit/merge method on ExecutionContext); add or call a
clearly named method such as exec_ctx.harvest_changes() or
exec_ctx.merge_back_to(workspace.repo_path) prior to cleanup, and ensure
_execute_task_subprocess and any agent tool functions remain stateless and write
only to the provided workspace_path; apply the same harvest-before-cleanup fix
at the other similar locations referenced (around the other ExecutionContext
usages).

In `@codeframe/core/runtime.py`:
- Around line 679-685: The HookContext and hook invocations are being built with
the shared repo path before the execution context is created, which breaks
isolation; move the create_execution_context(...) call (using
IsolationLevel(isolation) and workspace.repo_path) so exec_ctx =
create_execution_context(...) runs before constructing HookContext and before
any execute_hook(...) calls, then use exec_ctx.workspace_path (or
effective_repo_path) as the repo path when building HookContext and when calling
execute_hook(...) so hooks operate against the execution context workspace
rather than the main checkout; keep the same create_execution_context,
IsolationLevel, HookContext, execute_hook, and exec_ctx symbols when editing.
- Around line 602-603: The isolation/worktree setup (create_execution_context)
must be moved into the guarded execution path so failures don't bypass
fail_run(); change execute_agent so exec_ctx is declared/initialized to None
before the try, then call create_execution_context(...) inside the try block
(e.g., where execution begins) and only perform cleanup if exec_ctx is not None;
apply same pattern for the other occurrences that initialize execution contexts
(the blocks around create_execution_context and cleanup mentioned near lines
679-685 and 877-878), and ensure fail_run() still runs on exceptions.

In `@tests/core/test_sandbox_context.py`:
- Around line 23-48: The git_repo fixture creates a repo that may default to
"master", but TaskWorktree.create defaults to base_branch="main", causing tests
to fail; update the git_repo fixture to rename the current branch to "main"
after the initial commit (e.g., run a git branch -M main or equivalent
subprocess.run call) so the repo has a "main" branch available for
TaskWorktree.create and the WORKTREE tests.

---

Outside diff comments:
In `@codeframe/cli/app.py`:
- Around line 3490-3566: The batch_run command handler lacks the required
verbose flag; update the batch_run function signature to add a verbose: bool
parameter exposed as a Typer/Click Option (flags --verbose and -v, default
False, help="Enable detailed output") and thread that flag into whatever
logging/execution path currently uses engine/isolation (e.g., pass verbose into
the batch executor or set process/log level where engine or isolation are used).
Ensure the new option name is consistent with existing options and does not
conflict with engine or isolation parameters.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d472ceb3-3bf1-44d5-acd4-7a5fb5224bed

📥 Commits

Reviewing files that changed from the base of the PR and between 7d5caab and 01acead.

📒 Files selected for processing (6)
  • codeframe/cli/app.py
  • codeframe/core/conductor.py
  • codeframe/core/runtime.py
  • codeframe/core/sandbox/__init__.py
  • codeframe/core/sandbox/context.py
  • tests/core/test_sandbox_context.py

Comment on lines 557 to 559
isolate: bool = True,
isolation: str = "none",
) -> BatchRun:

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.

⚠️ Potential issue | 🟠 Major

Validate isolation before the batch is persisted.

isolation is stored as a raw string here and only converted inside the execution loops. If callers pass "cloud" or any invalid value, the first create_execution_context(...) raises after the batch has already been saved and moved to RUNNING, which leaves a half-started batch instead of a clean validation error.

🛠️ Suggested preflight validation
 def start_batch(
@@
     if not task_ids:
         raise ValueError("task_ids cannot be empty")
+
+    from codeframe.core.sandbox.context import IsolationLevel
+
+    try:
+        isolation_level = IsolationLevel(isolation)
+    except ValueError as exc:
+        raise ValueError(f"Unsupported isolation level: {isolation}") from exc
+    if isolation_level is IsolationLevel.CLOUD:
+        raise ValueError(
+            "Isolation level 'cloud' is not implemented yet. Use 'none' or 'worktree'."
+        )
@@
         concurrency=concurrency,
         isolate=isolate,
-        isolation=isolation,
+        isolation=isolation_level.value,
     )

Also applies to: 598-615

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@codeframe/core/conductor.py` around lines 557 - 559, Validate the isolation
parameter before persisting the batch: in the function that takes isolate: bool
and isolation: str -> BatchRun, check that isolation is one of the allowed
values (e.g., "none", "host", "container", "vm" or your project's canonical set)
and raise a clear validation error if not, before calling
create_execution_context(...) or saving/moving the batch to RUNNING; apply the
same preflight check for the similar block around create_execution_context usage
at the other location referenced (the code between the earlier
create_execution_context call and the block at 598-615) so no batch is persisted
when isolation is invalid.

Comment on lines +1020 to +1030
# Execute task via subprocess (with isolation context)
from codeframe.core.sandbox.context import IsolationLevel, create_execution_context
exec_ctx = create_execution_context(task_id, IsolationLevel(batch.isolation), workspace.repo_path)
try:
result_status = _execute_task_subprocess(
workspace, task_id, batch.id, engine=batch.engine,
stall_timeout_s=batch.stall_timeout_s, stall_action=batch.stall_action,
worktree_path=exec_ctx.workspace_path if exec_ctx.workspace_path != workspace.repo_path else None,
)
finally:
exec_ctx.cleanup()

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.

⚠️ Potential issue | 🔴 Critical

worktree runs currently delete their own outputs.

These paths tear the ExecutionContext down in finally, but there is no merge/copy/patch step before cleanup. Because task tools write against exec_ctx.workspace_path, a successful WORKTREE run leaves its edits in the task worktree and then deletes them here, so the batch can report success while workspace.repo_path stays unchanged. Harvest the worktree changes before cleanup, or keep the worktree around until a caller has done so.

Based on learnings, "agent tool functions ... must be stateless with signature (input_data: dict, workspace_path: Path, tool_call_id: str) -> ToolResult".

Also applies to: 1197-1207, 1426-1448, 1840-1870, 1960-1976

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@codeframe/core/conductor.py` around lines 1020 - 1030, The worktree created
by create_execution_context (ExecutionContext / exec_ctx) is torn down in the
finally block via exec_ctx.cleanup() without harvesting changes, so any edits
under exec_ctx.workspace_path are deleted; before calling exec_ctx.cleanup()
(after _execute_task_subprocess returns success or result_status is available)
detect when exec_ctx.workspace_path != workspace.repo_path and persist the
worktree edits back into the main workspace (e.g., by merging/patching/copying
changed files or invoking a commit/merge method on ExecutionContext); add or
call a clearly named method such as exec_ctx.harvest_changes() or
exec_ctx.merge_back_to(workspace.repo_path) prior to cleanup, and ensure
_execute_task_subprocess and any agent tool functions remain stateless and write
only to the provided workspace_path; apply the same harvest-before-cleanup fix
at the other similar locations referenced (around the other ExecutionContext
usages).

Comment on lines 2146 to +2149
INSERT OR REPLACE INTO batch_runs
(id, workspace_id, task_ids, status, strategy, max_parallel, on_failure,
started_at, completed_at, results, engine)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
started_at, completed_at, results, engine, isolation)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)

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.

⚠️ Potential issue | 🟠 Major

Loaded batches always fall back to isolation="none".

_row_to_batch() now expects row[11], but get_batch() and list_batches() still select only ... results, engine from batch_runs. Every reloaded batch therefore drops its stored isolation, so resume_batch() re-executes on the shared repo even if the original batch used worktree.

💾 Suggested query fix
         SELECT id, workspace_id, task_ids, status, strategy, max_parallel,
-               on_failure, started_at, completed_at, results, engine
+               on_failure, started_at, completed_at, results, engine, isolation
         FROM batch_runs
@@
             SELECT id, workspace_id, task_ids, status, strategy, max_parallel,
-                   on_failure, started_at, completed_at, results, engine
+                   on_failure, started_at, completed_at, results, engine, isolation
             FROM batch_runs
@@
             SELECT id, workspace_id, task_ids, status, strategy, max_parallel,
-                   on_failure, started_at, completed_at, results, engine
+                   on_failure, started_at, completed_at, results, engine, isolation
             FROM batch_runs

Also applies to: 2162-2163, 2171-2185

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@codeframe/core/conductor.py` around lines 2146 - 2149, The SELECTs that
populate rows for _row_to_batch() are missing the isolation column so loaded
batches default to "none"; update get_batch() and list_batches() (and any other
queries that fetch batch_runs rows used by _row_to_batch(), e.g., resume_batch
related queries) to include the isolation column in the SELECT list in the same
order as the INSERT (id, workspace_id, task_ids, status, strategy, max_parallel,
on_failure, started_at, completed_at, results, engine, isolation) so
_row_to_batch() reads isolation from row[11] correctly.

Comment thread codeframe/core/runtime.py
Comment on lines +602 to 603
isolation: str = "none",
) -> "AgentState":

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.

⚠️ Potential issue | 🔴 Critical

Move isolation setup under the guarded execution path.

create_execution_context() runs before the main try, so --isolation cloud (currently NotImplementedError) or any worktree setup failure exits execute_agent() before fail_run() runs. That leaves the run/task stuck active even though execution never started. Initialize exec_ctx first, create the context inside the try, and only clean it up when setup succeeded.

🛠️ Suggested fix
-    # Create execution context (handles isolation; NONE is a no-op)
-    from codeframe.core.sandbox.context import IsolationLevel, create_execution_context
-    exec_ctx = create_execution_context(
-        run.task_id, IsolationLevel(isolation), workspace.repo_path
-    )
-    effective_repo_path = exec_ctx.workspace_path
-
-    try:
+    # Create execution context (handles isolation; NONE is a no-op)
+    from codeframe.core.sandbox.context import IsolationLevel, create_execution_context
+    exec_ctx = None
+    effective_repo_path = workspace.repo_path
+
+    try:
+        exec_ctx = create_execution_context(
+            run.task_id, IsolationLevel(isolation), workspace.repo_path
+        )
+        effective_repo_path = exec_ctx.workspace_path
-        exec_ctx.cleanup()
+        if exec_ctx is not None:
+            exec_ctx.cleanup()

Also applies to: 679-685, 877-878

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@codeframe/core/runtime.py` around lines 602 - 603, The isolation/worktree
setup (create_execution_context) must be moved into the guarded execution path
so failures don't bypass fail_run(); change execute_agent so exec_ctx is
declared/initialized to None before the try, then call
create_execution_context(...) inside the try block (e.g., where execution
begins) and only perform cleanup if exec_ctx is not None; apply same pattern for
the other occurrences that initialize execution contexts (the blocks around
create_execution_context and cleanup mentioned near lines 679-685 and 877-878),
and ensure fail_run() still runs on exceptions.

Comment thread codeframe/core/runtime.py
Comment on lines +679 to +685
# Create execution context (handles isolation; NONE is a no-op)
from codeframe.core.sandbox.context import IsolationLevel, create_execution_context
exec_ctx = create_execution_context(
run.task_id, IsolationLevel(isolation), workspace.repo_path
)
effective_repo_path = exec_ctx.workspace_path

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.

⚠️ Potential issue | 🟠 Major

Create the context before building hook state.

Because the execution context is created after HookContext is assembled, Line 673 and the execute_hook(..., workspace.repo_path, ...) calls still point at the shared repo. With worktree isolation, before_task / after_task_* hooks can read or mutate the main checkout while the agent runs against the worktree, which breaks task isolation.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@codeframe/core/runtime.py` around lines 679 - 685, The HookContext and hook
invocations are being built with the shared repo path before the execution
context is created, which breaks isolation; move the
create_execution_context(...) call (using IsolationLevel(isolation) and
workspace.repo_path) so exec_ctx = create_execution_context(...) runs before
constructing HookContext and before any execute_hook(...) calls, then use
exec_ctx.workspace_path (or effective_repo_path) as the repo path when building
HookContext and when calling execute_hook(...) so hooks operate against the
execution context workspace rather than the main checkout; keep the same
create_execution_context, IsolationLevel, HookContext, execute_hook, and
exec_ctx symbols when editing.

Comment thread tests/core/test_sandbox_context.py
@claude

claude Bot commented Apr 3, 2026

Copy link
Copy Markdown

Follow-up Review: The latest commit only touches tests/core/test_sandbox_context.py with trivial changes. None of the critical issues from the previous review round have been addressed. Still open: (1) isolation column missing from SELECT queries in conductor.py - _row_to_batch reads row[11] but queries return only 11-element tuples, silently defaulting batch isolation to none on reload. (2) create_execution_context called outside try block in runtime.execute_agent() - a worktree creation failure leaves runs stuck in IN_PROGRESS. (3) No merge_back/harvest before cleanup() - worktree output is silently discarded. (4) Batch subprocess worktree not propagated - _execute_task_subprocess sets cwd=worktree_path but subprocess agent resolves workspace from DB repo_path; --isolation not forwarded in command array. (5) Bare except Exception: pass in DB migration swallows all errors. Suggested fix order matches CodeRabbit item order: SELECT queries first (data loss), then try-block fix, then merge-back, then migration guard, then subprocess forwarding.

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.

[Phase 4.B] ExecutionContext abstraction: local | worktree | e2b-sandbox

1 participant