mirror of
https://github.com/harivansh-afk/sandbox-agent.git
synced 2026-04-17 06:04:56 +00:00
Integrate OpenHandoff factory workspace (#212)
This commit is contained in:
parent
3d9476ed0b
commit
bf282199b5
251 changed files with 42824 additions and 692 deletions
40
factory/research/specs/frontend.md
Normal file
40
factory/research/specs/frontend.md
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
# frontend
|
||||
|
||||
we need to build a browser-friendly version of our tui. we should try to keep the tui and gui as close together as possible. add this to agents.md
|
||||
|
||||
be thorough and careful with your impelmentaiton. this is going to be the ground 0 for a lot of work so it needs to be clean and well structured with support for routing, clean state architecture, etc.
|
||||
|
||||
## tech
|
||||
|
||||
- vite
|
||||
- baseui
|
||||
- tanstack
|
||||
|
||||
## arch
|
||||
|
||||
- make sure that rivetkit is not imported in to either the cli or the gui. this should all be isoaletd in our client package. add this to agents.md
|
||||
|
||||
## agent session api
|
||||
|
||||
- expose the sandbox agent api on sandbox instance actor for managing sessions and sendin messages
|
||||
- agent session api should use @sandbox-agent/persist-rivet for persisting to rivet
|
||||
|
||||
## layout
|
||||
|
||||
- left sidebar is similar to the hf switch ui:
|
||||
- list each repo
|
||||
- under each repo, show all of the handoffs
|
||||
- you should see all handoffs for the entire workspace here grouped by repo
|
||||
- the main content area shows the current workspace
|
||||
- there is a main agent session for the main agent thatn's making the change, so show this by default
|
||||
- build a ui for interacting with sessions
|
||||
- see ~/sandbox-agent/frontend/packages/inspector/ for reference ui
|
||||
- right sidebar
|
||||
- show all information about the current handoff
|
||||
|
||||
## testing
|
||||
|
||||
- use agent-browser cli to veirfy that all of this functionality works
|
||||
- create handoff
|
||||
- can see the handoff in the sidear
|
||||
- clik on handoff to see the agent transcript
|
||||
554
factory/research/specs/rivetkit-opentui-migration-plan.md
Normal file
554
factory/research/specs/rivetkit-opentui-migration-plan.md
Normal file
|
|
@ -0,0 +1,554 @@
|
|||
# RivetKit + Sandbox Provider + OpenTUI Migration Spec
|
||||
|
||||
Status: implemented baseline (Phase 1-4 complete, Phase 5 partial)
|
||||
Date: 2026-02-08
|
||||
|
||||
## Locked Decisions
|
||||
|
||||
1. Entire rewrite is TypeScript. All Rust code will be deleted at cutover.
|
||||
2. Repo stays a single monorepo, managed with `pnpm` workspaces + Turborepo.
|
||||
3. `core` package is renamed to `shared`.
|
||||
4. `integrations` and `providers` live inside the backend package (not top-level packages).
|
||||
5. Rivet-backed state uses SQLite + Drizzle only.
|
||||
6. RivetKit dependencies come from local `../rivet` builds only; no published npm packages.
|
||||
7. Everything is workspace-scoped. Workspace is configurable from CLI.
|
||||
8. `ControlPlaneActor` is renamed to `WorkspaceActor` (workspace coordinator).
|
||||
9. Every actor key is prefixed by workspace.
|
||||
10. `--workspace` is optional; commands resolve workspace via flag -> config default -> `default`.
|
||||
11. RivetKit local dependency wiring is `link:`-based.
|
||||
12. Keep the existing config file path (`~/.config/openhandoff/config.toml`) and evolve keys in place.
|
||||
13. `.agents` and skill files are in scope for migration updates.
|
||||
14. Parent orchestration actors (`workspace`, `project`, `handoff`) use command-only loops with no timeout.
|
||||
15. Periodic syncing/polling runs in dedicated child actors, each with a single timeout cadence.
|
||||
16. For each actor, define the main loop and exactly what data it mutates; keep single-writer ownership strict.
|
||||
|
||||
## Executive Summary
|
||||
|
||||
We will replace the existing Rust backend/CLI/TUI with TypeScript services and UIs:
|
||||
|
||||
- Backend: RivetKit actor runtime
|
||||
- Agent orchestration: Sandbox Agent through provider adapters
|
||||
- CLI: TypeScript
|
||||
- TUI: TypeScript + OpenTUI
|
||||
- State: SQLite + Drizzle (actor-owned writes)
|
||||
|
||||
The core architecture changes from "worktree-per-handoff" to "provider-selected sandbox-per-handoff." Local worktrees remain supported through a `worktree` provider.
|
||||
|
||||
## Breaking Changes (Intentional)
|
||||
|
||||
1. Rust binaries/backend removed.
|
||||
2. Existing IPC replaced by new TypeScript transport.
|
||||
3. Configuration schema changes for workspace selection and sandbox provider defaults.
|
||||
4. Runtime model changes from global control plane to workspace coordinator actor.
|
||||
5. Database schema migrates to workspace + provider + sandbox identity model.
|
||||
6. Command options evolve to include workspace and provider selection.
|
||||
|
||||
## Monorepo and Build Tooling
|
||||
|
||||
Root tooling is standardized:
|
||||
|
||||
- `pnpm-workspace.yaml`
|
||||
- `turbo.json`
|
||||
- workspace scripts through `pnpm` + `turbo run ...`
|
||||
|
||||
Target package layout:
|
||||
|
||||
```text
|
||||
packages/
|
||||
shared/ # shared types, contracts, validation
|
||||
backend/
|
||||
src/
|
||||
actors/
|
||||
workspace.ts
|
||||
project.ts
|
||||
handoff.ts
|
||||
sandbox-instance.ts
|
||||
history.ts
|
||||
project-pr-sync.ts
|
||||
project-branch-sync.ts
|
||||
handoff-status-sync.ts
|
||||
keys.ts
|
||||
events.ts
|
||||
registry.ts
|
||||
index.ts
|
||||
providers/ # provider-api + implementations
|
||||
provider-api/
|
||||
worktree/
|
||||
daytona/
|
||||
integrations/ # sandbox-agent + git/github/graphite adapters
|
||||
sandbox-agent/
|
||||
git/
|
||||
github/
|
||||
graphite/
|
||||
db/ # drizzle schema, queries, migrations
|
||||
schema.ts
|
||||
client.ts
|
||||
migrations/
|
||||
transport/
|
||||
server.ts
|
||||
types.ts
|
||||
config/
|
||||
workspace.ts
|
||||
backend.ts
|
||||
cli/ # hf command surface
|
||||
src/
|
||||
commands/
|
||||
client/ # backend transport client
|
||||
workspace/ # workspace selection resolver
|
||||
tui/ # OpenTUI app
|
||||
src/
|
||||
app/
|
||||
views/
|
||||
state/
|
||||
client/ # backend stream client
|
||||
research/specs/
|
||||
rivetkit-opentui-migration-plan.md (this file)
|
||||
```
|
||||
|
||||
CLI and TUI are separate packages in the same monorepo, not separate repositories.
|
||||
|
||||
## Actor File Map (Concrete)
|
||||
|
||||
Backend actor files and responsibilities:
|
||||
|
||||
1. `packages/backend/src/actors/workspace.ts`
|
||||
- `WorkspaceActor` implementation.
|
||||
- Provider profile resolution and workspace-level coordination.
|
||||
- Spawns/routes to `ProjectActor` handles.
|
||||
|
||||
2. `packages/backend/src/actors/project.ts`
|
||||
- `ProjectActor` implementation.
|
||||
- Branch snapshot refresh, PR cache orchestration, stream publication.
|
||||
- Routes handoff actions to `HandoffActor`.
|
||||
|
||||
3. `packages/backend/src/actors/handoff.ts`
|
||||
- `HandoffActor` implementation.
|
||||
- Handoff lifecycle, session/sandbox orchestration, post-idle automation.
|
||||
|
||||
4. `packages/backend/src/actors/sandbox-instance.ts`
|
||||
- `SandboxInstanceActor` implementation.
|
||||
- Provider sandbox lifecycle, heartbeat, reconnect/recovery.
|
||||
|
||||
5. `packages/backend/src/actors/history.ts`
|
||||
- `HistoryActor` implementation.
|
||||
- Writes workflow events to SQLite via Drizzle.
|
||||
|
||||
6. `packages/backend/src/actors/keys.ts`
|
||||
- Workspace-prefixed actor key builders/parsers.
|
||||
|
||||
7. `packages/backend/src/actors/events.ts`
|
||||
- Internal actor event envelopes and stream payload types.
|
||||
|
||||
8. `packages/backend/src/actors/registry.ts`
|
||||
- RivetKit registry setup and actor registration.
|
||||
|
||||
9. `packages/backend/src/actors/index.ts`
|
||||
- Actor exports and composition wiring.
|
||||
|
||||
10. `packages/backend/src/actors/project-pr-sync.ts`
|
||||
- Read-only PR polling loop (single timeout cadence).
|
||||
- Sends sync results back to `ProjectActor`.
|
||||
|
||||
11. `packages/backend/src/actors/project-branch-sync.ts`
|
||||
- Read-only branch snapshot polling loop (single timeout cadence).
|
||||
- Sends sync results back to `ProjectActor`.
|
||||
|
||||
12. `packages/backend/src/actors/handoff-status-sync.ts`
|
||||
- Read-only session/sandbox status polling loop (single timeout cadence).
|
||||
- Sends status updates back to `HandoffActor`.
|
||||
|
||||
## RivetKit Source Policy (Local Only)
|
||||
|
||||
Do not use published RivetKit packages.
|
||||
|
||||
1. Build RivetKit from local source:
|
||||
```bash
|
||||
cd ../rivet
|
||||
pnpm build -F rivetkit
|
||||
```
|
||||
2. Consume via local `link:` dependencies to built artifacts.
|
||||
3. Keep dependency wiring deterministic and documented in repo scripts.
|
||||
|
||||
## Workspace Model
|
||||
|
||||
Every command executes against a resolved workspace context.
|
||||
|
||||
Workspace selection:
|
||||
|
||||
1. CLI flag: `--workspace <name>`
|
||||
2. Config default workspace
|
||||
3. Fallback to `default`
|
||||
|
||||
Workspace controls:
|
||||
|
||||
1. provider profile defaults
|
||||
2. sandbox policy
|
||||
3. repo membership / resolution
|
||||
4. actor namespaces and database partitioning
|
||||
|
||||
## New Actor Implementation Overview
|
||||
|
||||
RivetKit registry actor keys are workspace-prefixed:
|
||||
|
||||
1. `WorkspaceActor` (workspace coordinator)
|
||||
- Key: `["ws", workspaceId]`
|
||||
- Owns workspace config/runtime coordination, provider registry, workspace health.
|
||||
- Resolves provider defaults and workspace-level policies.
|
||||
|
||||
2. `ProjectActor`
|
||||
- Key: `["ws", workspaceId, "project", repoId]`
|
||||
- Owns repo snapshot cache and PR cache refresh orchestration.
|
||||
- Routes branch/handoff commands to handoff actors.
|
||||
- Streams project updates to CLI/TUI subscribers.
|
||||
|
||||
3. `HandoffActor`
|
||||
- Key: `["ws", workspaceId, "project", repoId, "handoff", handoffId]`
|
||||
- Owns handoff metadata/runtime state.
|
||||
- Creates/resumes sandbox + session through provider adapter.
|
||||
- Handles attach/push/sync/merge/archive/kill and post-idle automation.
|
||||
|
||||
4. `SandboxInstanceActor` (optional but recommended)
|
||||
- Key: `["ws", workspaceId, "provider", providerId, "sandbox", sandboxId]`
|
||||
- Owns sandbox lifecycle, heartbeat, endpoint readiness, recovery.
|
||||
|
||||
5. `HistoryActor`
|
||||
- Key: `["ws", workspaceId, "project", repoId, "history"]`
|
||||
- Owns `events` writes and workflow timeline completeness.
|
||||
|
||||
6. `ProjectPrSyncActor` (child poller)
|
||||
- Key: `["ws", workspaceId, "project", repoId, "pr-sync"]`
|
||||
- Polls PR state on interval and emits results to `ProjectActor`.
|
||||
- Does not write DB directly.
|
||||
|
||||
7. `ProjectBranchSyncActor` (child poller)
|
||||
- Key: `["ws", workspaceId, "project", repoId, "branch-sync"]`
|
||||
- Polls branch/worktree state on interval and emits results to `ProjectActor`.
|
||||
- Does not write DB directly.
|
||||
|
||||
8. `HandoffStatusSyncActor` (child poller)
|
||||
- Key: `["ws", workspaceId, "project", repoId, "handoff", handoffId, "status-sync"]`
|
||||
- Polls agent/session/sandbox health on interval and emits results to `HandoffActor`.
|
||||
- Does not write DB directly.
|
||||
|
||||
Ownership rule: each table/row has one actor writer.
|
||||
|
||||
## Single-Writer Mutation Map
|
||||
|
||||
Always define actor run-loop + mutated state together:
|
||||
|
||||
1. `WorkspaceActor`
|
||||
- Mutates: `workspaces`, `workspace_provider_profiles`.
|
||||
|
||||
2. `ProjectActor`
|
||||
- Mutates: `repos`, `branches`, `pr_cache` (applies child poller results).
|
||||
|
||||
3. `HandoffActor`
|
||||
- Mutates: `handoffs`, `handoff_runtime` (applies child poller results).
|
||||
|
||||
4. `SandboxInstanceActor`
|
||||
- Mutates: `sandbox_instances`.
|
||||
|
||||
5. `HistoryActor`
|
||||
- Mutates: `events`.
|
||||
|
||||
6. Child sync actors (`project-pr-sync`, `project-branch-sync`, `handoff-status-sync`)
|
||||
- Mutates: none (read-only pollers; publish result messages only).
|
||||
|
||||
## Run Loop Patterns (Required)
|
||||
|
||||
Parent orchestration actors: no timeout, command-only queue loops.
|
||||
|
||||
### `WorkspaceActor` (no timeout)
|
||||
|
||||
```ts
|
||||
run: async (c) => {
|
||||
while (true) {
|
||||
const msg = await c.queue.next("workspace.command");
|
||||
await handleWorkspaceCommand(c, msg); // writes workspace-owned tables only
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### `ProjectActor` (no timeout)
|
||||
|
||||
```ts
|
||||
run: async (c) => {
|
||||
while (true) {
|
||||
const msg = await c.queue.next("project.command");
|
||||
await handleProjectCommand(c, msg); // includes applying sync results to branches/pr_cache
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### `HandoffActor` (no timeout)
|
||||
|
||||
```ts
|
||||
run: async (c) => {
|
||||
while (true) {
|
||||
const msg = await c.queue.next("handoff.command");
|
||||
await handleHandoffCommand(c, msg); // includes applying status results to handoff_runtime
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### `SandboxInstanceActor` (no timeout)
|
||||
|
||||
```ts
|
||||
run: async (c) => {
|
||||
while (true) {
|
||||
const msg = await c.queue.next("sandbox_instance.command");
|
||||
await handleSandboxInstanceCommand(c, msg); // sandbox_instances table only
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### `HistoryActor` (no timeout)
|
||||
|
||||
```ts
|
||||
run: async (c) => {
|
||||
while (true) {
|
||||
const msg = await c.queue.next("history.command");
|
||||
await persistEvent(c, msg); // events table only
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
Child sync actors: one timeout each, one cadence each.
|
||||
|
||||
### `ProjectPrSyncActor` (single timeout cadence)
|
||||
|
||||
```ts
|
||||
run: async (c) => {
|
||||
const intervalMs = 30_000;
|
||||
while (true) {
|
||||
const msg = await c.queue.next("project.pr_sync.command", { timeout: intervalMs });
|
||||
if (!msg) {
|
||||
const result = await pollPrState();
|
||||
await sendToProject({ name: "project.pr_sync.result", result });
|
||||
continue;
|
||||
}
|
||||
await handlePrSyncControl(c, msg); // force/stop/update-interval
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### `ProjectBranchSyncActor` (single timeout cadence)
|
||||
|
||||
```ts
|
||||
run: async (c) => {
|
||||
const intervalMs = 5_000;
|
||||
while (true) {
|
||||
const msg = await c.queue.next("project.branch_sync.command", { timeout: intervalMs });
|
||||
if (!msg) {
|
||||
const result = await pollBranchState();
|
||||
await sendToProject({ name: "project.branch_sync.result", result });
|
||||
continue;
|
||||
}
|
||||
await handleBranchSyncControl(c, msg);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### `HandoffStatusSyncActor` (single timeout cadence)
|
||||
|
||||
```ts
|
||||
run: async (c) => {
|
||||
const intervalMs = 2_000;
|
||||
while (true) {
|
||||
const msg = await c.queue.next("handoff.status_sync.command", { timeout: intervalMs });
|
||||
if (!msg) {
|
||||
const result = await pollSessionAndSandboxStatus();
|
||||
await sendToHandoff({ name: "handoff.status_sync.result", result });
|
||||
continue;
|
||||
}
|
||||
await handleStatusSyncControl(c, msg);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## Sandbox Provider Interface
|
||||
|
||||
Provider contract lives under `packages/backend/src/providers/provider-api` and is consumed by workspace/project/handoff actors.
|
||||
|
||||
```ts
|
||||
interface SandboxProvider {
|
||||
id(): string;
|
||||
capabilities(): ProviderCapabilities;
|
||||
validateConfig(input: unknown): Promise<ValidatedConfig>;
|
||||
|
||||
createSandbox(req: CreateSandboxRequest): Promise<SandboxHandle>;
|
||||
resumeSandbox(req: ResumeSandboxRequest): Promise<SandboxHandle>;
|
||||
destroySandbox(req: DestroySandboxRequest): Promise<void>;
|
||||
|
||||
ensureSandboxAgent(req: EnsureAgentRequest): Promise<AgentEndpoint>;
|
||||
health(req: SandboxHealthRequest): Promise<SandboxHealth>;
|
||||
attachTarget(req: AttachTargetRequest): Promise<AttachTarget>;
|
||||
}
|
||||
```
|
||||
|
||||
Initial providers:
|
||||
|
||||
1. `worktree`
|
||||
- Local git worktree-backed sandbox.
|
||||
- Sandbox Agent local/shared endpoint.
|
||||
- Preserves tmux + `cd` ergonomics.
|
||||
|
||||
2. `daytona`
|
||||
- Remote sandbox lifecycle via Daytona.
|
||||
- Boots/ensures Sandbox Agent inside sandbox.
|
||||
- Returns endpoint/token for session operations.
|
||||
|
||||
## Command Surface (Workspace + Provider Aware)
|
||||
|
||||
1. `hf create ... --workspace <ws> --provider <worktree|daytona>`
|
||||
2. `hf switch --workspace <ws> [target]`
|
||||
3. `hf attach --workspace <ws> [handoff]`
|
||||
4. `hf list --workspace <ws>`
|
||||
5. `hf kill|archive|merge|push|sync --workspace <ws> ...`
|
||||
6. `hf workspace use <ws>` to set default workspace
|
||||
|
||||
List/TUI include provider and sandbox health metadata.
|
||||
|
||||
`--workspace` remains optional; omitted values use the standard resolution order.
|
||||
|
||||
## Data Model v2 (SQLite + Drizzle)
|
||||
|
||||
All persistent state is SQLite via Drizzle schema + migrations.
|
||||
|
||||
Tables (workspace-scoped):
|
||||
|
||||
1. `workspaces`
|
||||
2. `workspace_provider_profiles`
|
||||
3. `repos` (`workspace_id`, `repo_id`, ...)
|
||||
4. `branches` (`workspace_id`, `repo_id`, ...)
|
||||
5. `handoffs` (`workspace_id`, `handoff_id`, `provider_id`, ...)
|
||||
6. `handoff_runtime` (`workspace_id`, `handoff_id`, `sandbox_id`, `session_id`, ...)
|
||||
7. `sandbox_instances` (`workspace_id`, `provider_id`, `sandbox_id`, ...)
|
||||
8. `pr_cache` (`workspace_id`, `repo_id`, ...)
|
||||
9. `events` (`workspace_id`, `repo_id`, ...)
|
||||
|
||||
Migration approach: one-way migration from existing schema during TS backend bootstrap.
|
||||
|
||||
## Transport and Runtime
|
||||
|
||||
1. TypeScript backend exposes local control API (socket or localhost HTTP).
|
||||
2. CLI/TUI are thin clients; all mutations go through backend actors.
|
||||
3. OpenTUI subscribes to project streams from workspace-scoped project actors.
|
||||
4. Workspace is required context on all backend mutation requests.
|
||||
|
||||
CLI/TUI are responsible for resolving workspace context before calling backend mutations.
|
||||
|
||||
## CLI + TUI Packaging
|
||||
|
||||
CLI and TUI ship from one package:
|
||||
|
||||
1. `packages/cli`
|
||||
- command-oriented UX (`hf create`, `hf push`, scripting, JSON output)
|
||||
- interactive OpenTUI mode via `hf tui`
|
||||
- shared client/runtime wiring in one distributable
|
||||
|
||||
The package still calls the same backend API and shares contracts from `packages/shared`.
|
||||
|
||||
## Implementation Phases
|
||||
|
||||
## Phase 0: Contracts and Workspace Spec
|
||||
|
||||
1. Freeze workspace model, provider contract, and actor ownership map.
|
||||
2. Freeze command flags for workspace + provider selection.
|
||||
3. Define Drizzle schema draft and migration plan.
|
||||
|
||||
Exit criteria:
|
||||
- Approved architecture RFC.
|
||||
|
||||
## Phase 1: TypeScript Monorepo Bootstrap
|
||||
|
||||
1. Add `pnpm` workspace + Turborepo pipeline.
|
||||
2. Create `shared`, `backend`, and `cli` packages (with TUI integrated into CLI).
|
||||
3. Add strict TypeScript config and CI checks.
|
||||
|
||||
Exit criteria:
|
||||
- `pnpm -w typecheck` and `turbo run build` pass.
|
||||
|
||||
## Phase 2: RivetKit + Drizzle Foundations
|
||||
|
||||
1. Wire local RivetKit dependency from `../rivet`.
|
||||
2. Add SQLite + Drizzle migrations and query layer.
|
||||
3. Implement actor registry with workspace-prefixed keys.
|
||||
|
||||
Exit criteria:
|
||||
- Backend boot + workspace actor health checks pass.
|
||||
|
||||
## Phase 3: Provider Layer in Backend
|
||||
|
||||
1. Implement provider API inside backend package.
|
||||
2. Implement `worktree` provider end-to-end.
|
||||
3. Integrate sandbox-agent session lifecycle through provider.
|
||||
|
||||
Exit criteria:
|
||||
- `create/list/switch/attach/push/sync/kill` pass on worktree provider.
|
||||
|
||||
## Phase 4: Workspace/Handoff Lifecycle
|
||||
|
||||
1. Implement workspace coordinator flows.
|
||||
2. Implement HandoffActor full lifecycle + post-idle automation.
|
||||
3. Implement history events and PR/CI/review change tracking.
|
||||
|
||||
Exit criteria:
|
||||
- history/event completeness with parity checks.
|
||||
|
||||
## Phase 5: Daytona Provider
|
||||
|
||||
1. Implement Daytona sandbox lifecycle adapter.
|
||||
2. Ensure sandbox-agent boot and reconnection behavior.
|
||||
3. Validate attach/switch/kill flows for remote sandboxes.
|
||||
|
||||
Exit criteria:
|
||||
- e2e pass on daytona provider.
|
||||
|
||||
## Phase 6: OpenTUI Rewrite
|
||||
|
||||
1. Build interactive list/switch UI in OpenTUI.
|
||||
2. Implement key actions (attach/open PR/archive/merge/sync).
|
||||
3. Add workspace switcher UX and provider/sandbox indicators.
|
||||
|
||||
Exit criteria:
|
||||
- TUI parity and responsive streaming updates.
|
||||
|
||||
## Phase 7: Cutover + Rust Deletion
|
||||
|
||||
1. Migrate existing DB to v2.
|
||||
2. Replace runtime entrypoints with TS CLI/backend/TUI.
|
||||
3. Delete Rust code, Cargo files, Rust scripts.
|
||||
4. Update docs and `skills/SKILL.md`.
|
||||
|
||||
Exit criteria:
|
||||
- no Rust code remains, fresh install + upgrade validated.
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
1. Unit tests
|
||||
- actor actions and ownership rules
|
||||
- provider adapters
|
||||
- event emission correctness
|
||||
- drizzle query/migration tests
|
||||
|
||||
2. Integration tests
|
||||
- backend + sqlite + provider fakes
|
||||
- workspace isolation boundaries
|
||||
- session recovery and restart handling
|
||||
|
||||
3. E2E tests
|
||||
- worktree provider in local test repo
|
||||
- daytona provider in controlled env
|
||||
- OpenTUI interactive flows
|
||||
|
||||
4. Reliability tests
|
||||
- sandbox-agent restarts
|
||||
- transient provider failures
|
||||
- backend restart with in-flight handoffs
|
||||
|
||||
## Open Questions To Resolve Before Implementation
|
||||
|
||||
1. Daytona production adapter parity:
|
||||
- Current `daytona` provider in this repo is intentionally a fallback adapter so local development remains testable without a Daytona backend.
|
||||
- Final deployment integration should replace placeholder lifecycle calls with Daytona API operations (create/destroy/health/auth/session boot inside sandbox).
|
||||
Loading…
Add table
Add a link
Reference in a new issue