Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 16 additions & 4 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,12 +153,21 @@ codeframe/
│ ├── stall_detector.py # Synchronous stall detector + StallAction enum + StallDetectedError
│ ├── stall_monitor.py # Thread-based stall watchdog with callback
│ ├── streaming.py # Real-time output streaming for cf work follow
│ ├── worktrees.py # TaskWorktree, WorktreeRegistry, get_base_branch
│ ├── sandbox/ # Execution isolation abstractions
│ │ ├── context.py # ExecutionContext + IsolationLevel (none/worktree/cloud)
│ │ └── worktree.py # Re-exports worktree symbols from core/worktrees.py
│ └── ...
├── adapters/
│ └── llm/ # LLM provider adapters
│ ├── base.py # Protocol + ModelSelector + Purpose enum
│ ├── anthropic.py # Anthropic Claude provider
│ └── mock.py # Mock provider for testing
│ ├── llm/ # LLM provider adapters
│ │ ├── base.py # Protocol + ModelSelector + Purpose enum
│ │ ├── anthropic.py # Anthropic Claude provider
│ │ └── mock.py # Mock provider for testing
│ └── e2b/ # E2B cloud sandbox adapter (optional — requires `pip install codeframe[cloud]`)
│ ├── __init__.py # Exports E2BAgentAdapter
│ ├── adapter.py # E2BAgentAdapter (engine="cloud")
│ ├── budget.py # Cost tracking utilities
│ └── credential_scanner.py # Pre-upload secrets scanner
├── cli/
│ └── app.py # Typer CLI entry + subcommands
├── ui/ # FastAPI server (Phase 2 - thin adapter over core)
Expand Down Expand Up @@ -884,6 +893,9 @@ uv run pytest --cov=codeframe --cov-report=html
# Required for agent execution
ANTHROPIC_API_KEY=sk-ant-...

# Required for cloud sandbox execution (--engine cloud)
E2B_API_KEY=e2b_...

# Optional - Database
DATABASE_PATH=./codeframe.db

Expand Down
18 changes: 16 additions & 2 deletions codeframe/core/sandbox/__init__.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,27 @@
"""Execution environment sandbox abstraction.

Provides ExecutionContext and IsolationLevel for isolating task execution
from the shared filesystem.
from the shared filesystem, plus worktree registry helpers.
"""

from codeframe.core.sandbox.context import (
ExecutionContext,
IsolationLevel,
create_execution_context,
)
from codeframe.core.sandbox.worktree import (
MergeResult,
TaskWorktree,
WorktreeRegistry,
get_base_branch,
)

__all__ = ["ExecutionContext", "IsolationLevel", "create_execution_context"]
__all__ = [
"ExecutionContext",
"IsolationLevel",
"create_execution_context",
"MergeResult",
"TaskWorktree",
"WorktreeRegistry",
"get_base_branch",
]
20 changes: 20 additions & 0 deletions codeframe/core/sandbox/worktree.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
"""Worktree registry re-export for the sandbox namespace.

Re-exports ``TaskWorktree``, ``MergeResult``, ``WorktreeRegistry``, and
``get_base_branch`` from ``codeframe.core.worktrees`` so callers can import
from a single ``codeframe.core.sandbox`` sub-package.
"""

from codeframe.core.worktrees import (
MergeResult,
TaskWorktree,
WorktreeRegistry,
get_base_branch,
)

__all__ = [
"MergeResult",
"TaskWorktree",
"WorktreeRegistry",
"get_base_branch",
]
30 changes: 15 additions & 15 deletions docs/V2_STRATEGIC_ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -278,15 +278,15 @@ Phase 4 has three parallel tracks:

**Motivation**: `cf work batch run --strategy parallel` currently runs concurrent threads on the same filesystem with no isolation. Agents can corrupt each other's work, hit git index locks, or overwrite changes.

**Integration strategy**: `parallel-cc` is a production-grade tool that already solves this with git worktrees + E2B cloud sandboxes. It will be consumed as a dependency initially, then absorbed into CodeFrame as the integration matures. It will not remain a separate independent project long-term.
**Status**: The execution environment layer is complete. Worktree isolation and E2B cloud execution are fully absorbed into CodeFrame's own namespace — no external dependency was ever introduced.

#### Absorption arc
#### Absorption arc (complete ✅)

| Phase | What happens |
|-------|-------------|
| **Dependency** (now → Phase 4) | CodeFrame calls `parallel-cc` CLI/library for worktree + E2B management |
| **Integration** (during Phase 4) | parallel-cc concepts formalized as CodeFrame `ExecutionContext` abstraction |
| **Absorption** (Phase 4 complete) | parallel-cc code moves into `codeframe/core/sandbox/` and `codeframe/adapters/e2b/` |
| Phase | What happened |
|-------|--------------|
| ~~**Dependency**~~ | Skipped — logic was ported directly (parallel-cc never added as a dep) |
| **Integration** (Phase 4) | ✅ `ExecutionContext` abstraction formalized in `core/sandbox/context.py` |
| **Absorption** (Phase 4.B complete) | ✅ Worktree code in `core/worktrees.py` + `core/sandbox/worktree.py`; E2B adapter in `adapters/e2b/` |

#### Deliverables

Expand All @@ -296,9 +296,9 @@ Phase 4 has three parallel tracks:
- CLI: `--isolation none | worktree | cloud`

2. **Worktree isolation for parallel batch** (codeframe-c0rx)
- Each parallel task gets its own git worktree via `gtr` (from parallel-cc)
- Atomic session registration prevents race conditions
- Auto-cleanup on task completion
- Each parallel task gets its own git worktree via `TaskWorktree` (`core/worktrees.py`)
- `WorktreeRegistry` provides atomic session registration (prevents race conditions)
- Auto-cleanup on task completion via `ExecutionContext.cleanup()`
- Fixes the live filesystem conflict problem in `conductor.py`

3. **`E2BAgentAdapter`** (codeframe-csyd)
Expand All @@ -307,10 +307,10 @@ Phase 4 has three parallel tracks:
- Up to 1-hour autonomous execution with timeout management
- Budget tracking per task/batch

4. **parallel-cc absorption** (codeframe-xz0f)
- Port worktree coordination logic to `codeframe/core/sandbox/`
- Port E2B pipeline to `codeframe/adapters/e2b/`
- parallel-cc repo archived once absorption is complete
4. **parallel-cc absorption** (codeframe-xz0f)
- Worktree coordination lives in `codeframe/core/worktrees.py` and `codeframe/core/sandbox/`
- E2B pipeline lives in `codeframe/adapters/e2b/`
- parallel-cc was never added as a dependency; repo archived

---

Expand Down Expand Up @@ -346,7 +346,7 @@ Phase 4 has three parallel tracks:
| codeframe-la86 | ExecutionContext abstraction | 4.B | HIGH |
| codeframe-c0rx | Worktree isolation for parallel batch | 4.B | HIGH |
| codeframe-csyd | E2BAgentAdapter (cloud execution) | 4.B | MEDIUM |
| codeframe-xz0f | parallel-cc absorption into CodeFrame | 4.B | MEDIUM |
| codeframe-xz0f | parallel-cc absorption into CodeFrame | 4.B | MEDIUM |
| #310 | Agent roles | 4.C | MEDIUM |
| #311 | Conflict detection & resolution | 4.C | MEDIUM |
| #312 | Handoff protocols | 4.C | MEDIUM |
Expand Down
27 changes: 27 additions & 0 deletions tests/core/test_sandbox_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
create_execution_context,
)

pytestmark = pytest.mark.v2


@pytest.fixture
def git_repo(tmp_path: Path) -> Path:
Expand Down Expand Up @@ -153,3 +155,28 @@ class TestCreateExecutionContextCloud:
def test_raises_not_implemented(self, tmp_path: Path):
with pytest.raises(NotImplementedError, match="E2B"):
create_execution_context("task-1", IsolationLevel.CLOUD, tmp_path)


class TestSandboxWorktreeReexports:
"""sandbox.worktree re-exports resolve correctly (issue #535)."""

def test_task_worktree_importable_from_sandbox(self):
from codeframe.core.sandbox import TaskWorktree
assert TaskWorktree is not None

def test_merge_result_importable_from_sandbox(self):
from codeframe.core.sandbox import MergeResult
assert MergeResult is not None

def test_worktree_registry_importable_from_sandbox(self):
from codeframe.core.sandbox import WorktreeRegistry
assert WorktreeRegistry is not None

def test_get_base_branch_importable_from_sandbox(self):
from codeframe.core.sandbox import get_base_branch
assert callable(get_base_branch)

def test_sandbox_worktree_module_importable(self):
from codeframe.core.sandbox import worktree as wt_mod
assert hasattr(wt_mod, "TaskWorktree")
assert hasattr(wt_mod, "WorktreeRegistry")
Loading