mirror of
https://github.com/harivansh-afk/sandbox-agent.git
synced 2026-04-22 02:03:49 +00:00
wip
This commit is contained in:
parent
3263d4f5e1
commit
0fbea6ce61
166 changed files with 6675 additions and 7105 deletions
|
|
@ -6,19 +6,19 @@ 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.
|
||||
2. Repo stays a single monorepo, managed with `pnpm` organizations + 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`.
|
||||
7. Everything is organization-scoped. Organization is configurable from CLI.
|
||||
8. `ControlPlaneActor` is renamed to `OrganizationActor` (organization coordinator).
|
||||
9. Every actor key is prefixed by organization.
|
||||
10. `--organization` is optional; commands resolve organization via flag -> config default -> `default`.
|
||||
11. RivetKit local dependency wiring is `link:`-based.
|
||||
12. Keep the existing config file path (`~/.config/foundry/config.toml`) and evolve keys in place.
|
||||
13. `.agents` and skill files are in scope for migration updates.
|
||||
14. Parent orchestration actors (`workspace`, `project`, `task`) use command-only loops with no timeout.
|
||||
14. Parent orchestration actors (`organization`, `repository`, `task`) 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.
|
||||
|
||||
|
|
@ -38,10 +38,10 @@ The core architecture changes from "worktree-per-task" to "provider-selected san
|
|||
|
||||
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.
|
||||
3. Configuration schema changes for organization selection and sandbox provider defaults.
|
||||
4. Runtime model changes from global control plane to organization coordinator actor.
|
||||
5. Database schema migrates to organization + provider + sandbox identity model.
|
||||
6. Command options evolve to include organization and provider selection.
|
||||
|
||||
## Monorepo and Build Tooling
|
||||
|
||||
|
|
@ -49,7 +49,7 @@ Root tooling is standardized:
|
|||
|
||||
- `pnpm-workspace.yaml`
|
||||
- `turbo.json`
|
||||
- workspace scripts through `pnpm` + `turbo run ...`
|
||||
- organization scripts through `pnpm` + `turbo run ...`
|
||||
|
||||
Target package layout:
|
||||
|
||||
|
|
@ -59,13 +59,13 @@ packages/
|
|||
backend/
|
||||
src/
|
||||
actors/
|
||||
workspace.ts
|
||||
project.ts
|
||||
organization.ts
|
||||
repository.ts
|
||||
task.ts
|
||||
sandbox-instance.ts
|
||||
history.ts
|
||||
project-pr-sync.ts
|
||||
project-branch-sync.ts
|
||||
repository-pr-sync.ts
|
||||
repository-branch-sync.ts
|
||||
task-status-sync.ts
|
||||
keys.ts
|
||||
events.ts
|
||||
|
|
@ -88,13 +88,13 @@ packages/
|
|||
server.ts
|
||||
types.ts
|
||||
config/
|
||||
workspace.ts
|
||||
organization.ts
|
||||
backend.ts
|
||||
cli/ # hf command surface
|
||||
src/
|
||||
commands/
|
||||
client/ # backend transport client
|
||||
workspace/ # workspace selection resolver
|
||||
organization/ # organization selection resolver
|
||||
tui/ # OpenTUI app
|
||||
src/
|
||||
app/
|
||||
|
|
@ -111,13 +111,13 @@ CLI and TUI are separate packages in the same monorepo, not separate repositorie
|
|||
|
||||
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.
|
||||
1. `packages/backend/src/actors/organization.ts`
|
||||
- `OrganizationActor` implementation.
|
||||
- Provider profile resolution and organization-level coordination.
|
||||
- Spawns/routes to `RepositoryActor` handles.
|
||||
|
||||
2. `packages/backend/src/actors/project.ts`
|
||||
- `ProjectActor` implementation.
|
||||
2. `packages/backend/src/actors/repository.ts`
|
||||
- `RepositoryActor` implementation.
|
||||
- Branch snapshot refresh, PR cache orchestration, stream publication.
|
||||
- Routes task actions to `TaskActor`.
|
||||
|
||||
|
|
@ -134,7 +134,7 @@ Backend actor files and responsibilities:
|
|||
- Writes workflow events to SQLite via Drizzle.
|
||||
|
||||
6. `packages/backend/src/actors/keys.ts`
|
||||
- Workspace-prefixed actor key builders/parsers.
|
||||
- Organization-prefixed actor key builders/parsers.
|
||||
|
||||
7. `packages/backend/src/actors/events.ts`
|
||||
- Internal actor event envelopes and stream payload types.
|
||||
|
|
@ -145,13 +145,13 @@ Backend actor files and responsibilities:
|
|||
9. `packages/backend/src/actors/index.ts`
|
||||
- Actor exports and composition wiring.
|
||||
|
||||
10. `packages/backend/src/actors/project-pr-sync.ts`
|
||||
10. `packages/backend/src/actors/repository-pr-sync.ts`
|
||||
- Read-only PR polling loop (single timeout cadence).
|
||||
- Sends sync results back to `ProjectActor`.
|
||||
- Sends sync results back to `RepositoryActor`.
|
||||
|
||||
11. `packages/backend/src/actors/project-branch-sync.ts`
|
||||
11. `packages/backend/src/actors/repository-branch-sync.ts`
|
||||
- Read-only branch snapshot polling loop (single timeout cadence).
|
||||
- Sends sync results back to `ProjectActor`.
|
||||
- Sends sync results back to `RepositoryActor`.
|
||||
|
||||
12. `packages/backend/src/actors/task-status-sync.ts`
|
||||
- Read-only session/sandbox status polling loop (single timeout cadence).
|
||||
|
|
@ -169,17 +169,17 @@ 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
|
||||
## Organization Model
|
||||
|
||||
Every command executes against a resolved workspace context.
|
||||
Every command executes against a resolved organization context.
|
||||
|
||||
Workspace selection:
|
||||
Organization selection:
|
||||
|
||||
1. CLI flag: `--workspace <name>`
|
||||
2. Config default workspace
|
||||
1. CLI flag: `--organization <name>`
|
||||
2. Config default organization
|
||||
3. Fallback to `default`
|
||||
|
||||
Workspace controls:
|
||||
Organization controls:
|
||||
|
||||
1. provider profile defaults
|
||||
2. sandbox policy
|
||||
|
|
@ -188,45 +188,45 @@ Workspace controls:
|
|||
|
||||
## New Actor Implementation Overview
|
||||
|
||||
RivetKit registry actor keys are workspace-prefixed:
|
||||
RivetKit registry actor keys are organization-prefixed:
|
||||
|
||||
1. `WorkspaceActor` (workspace coordinator)
|
||||
- Key: `["ws", workspaceId]`
|
||||
- Owns workspace config/runtime coordination, provider registry, workspace health.
|
||||
- Resolves provider defaults and workspace-level policies.
|
||||
1. `OrganizationActor` (organization coordinator)
|
||||
- Key: `["ws", organizationId]`
|
||||
- Owns organization config/runtime coordination, provider registry, organization health.
|
||||
- Resolves provider defaults and organization-level policies.
|
||||
|
||||
2. `ProjectActor`
|
||||
- Key: `["ws", workspaceId, "project", repoId]`
|
||||
2. `RepositoryActor`
|
||||
- Key: `["ws", organizationId, "repository", repoId]`
|
||||
- Owns repo snapshot cache and PR cache refresh orchestration.
|
||||
- Routes branch/task commands to task actors.
|
||||
- Streams project updates to CLI/TUI subscribers.
|
||||
- Streams repository updates to CLI/TUI subscribers.
|
||||
|
||||
3. `TaskActor`
|
||||
- Key: `["ws", workspaceId, "project", repoId, "task", taskId]`
|
||||
- Key: `["ws", organizationId, "repository", repoId, "task", taskId]`
|
||||
- Owns task 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]`
|
||||
- Key: `["ws", organizationId, "provider", providerId, "sandbox", sandboxId]`
|
||||
- Owns sandbox lifecycle, heartbeat, endpoint readiness, recovery.
|
||||
|
||||
5. `HistoryActor`
|
||||
- Key: `["ws", workspaceId, "project", repoId, "history"]`
|
||||
- Key: `["ws", organizationId, "repository", 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`.
|
||||
- Key: `["ws", organizationId, "repository", repoId, "pr-sync"]`
|
||||
- Polls PR state on interval and emits results to `RepositoryActor`.
|
||||
- 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`.
|
||||
- Key: `["ws", organizationId, "repository", repoId, "branch-sync"]`
|
||||
- Polls branch/worktree state on interval and emits results to `RepositoryActor`.
|
||||
- Does not write DB directly.
|
||||
|
||||
8. `TaskStatusSyncActor` (child poller)
|
||||
- Key: `["ws", workspaceId, "project", repoId, "task", taskId, "status-sync"]`
|
||||
- Key: `["ws", organizationId, "repository", repoId, "task", taskId, "status-sync"]`
|
||||
- Polls agent/session/sandbox health on interval and emits results to `TaskActor`.
|
||||
- Does not write DB directly.
|
||||
|
||||
|
|
@ -236,10 +236,10 @@ Ownership rule: each table/row has one actor writer.
|
|||
|
||||
Always define actor run-loop + mutated state together:
|
||||
|
||||
1. `WorkspaceActor`
|
||||
- Mutates: `workspaces`, `workspace_provider_profiles`.
|
||||
1. `OrganizationActor`
|
||||
- Mutates: `organizations`, `workspace_provider_profiles`.
|
||||
|
||||
2. `ProjectActor`
|
||||
2. `RepositoryActor`
|
||||
- Mutates: `repos`, `branches`, `pr_cache` (applies child poller results).
|
||||
|
||||
3. `TaskActor`
|
||||
|
|
@ -251,30 +251,30 @@ Always define actor run-loop + mutated state together:
|
|||
5. `HistoryActor`
|
||||
- Mutates: `events`.
|
||||
|
||||
6. Child sync actors (`project-pr-sync`, `project-branch-sync`, `task-status-sync`)
|
||||
6. Child sync actors (`repository-pr-sync`, `repository-branch-sync`, `task-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)
|
||||
### `OrganizationActor` (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
|
||||
const msg = await c.queue.next("organization.command");
|
||||
await handleOrganizationCommand(c, msg); // writes organization-owned tables only
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### `ProjectActor` (no timeout)
|
||||
### `RepositoryActor` (no timeout)
|
||||
|
||||
```ts
|
||||
run: async (c) => {
|
||||
while (true) {
|
||||
const msg = await c.queue.next("project.command");
|
||||
const msg = await c.queue.next("repository.command");
|
||||
await handleProjectCommand(c, msg); // includes applying sync results to branches/pr_cache
|
||||
}
|
||||
};
|
||||
|
|
@ -321,10 +321,10 @@ Child sync actors: one timeout each, one cadence each.
|
|||
run: async (c) => {
|
||||
const intervalMs = 30_000;
|
||||
while (true) {
|
||||
const msg = await c.queue.next("project.pr_sync.command", { timeout: intervalMs });
|
||||
const msg = await c.queue.next("repository.pr_sync.command", { timeout: intervalMs });
|
||||
if (!msg) {
|
||||
const result = await pollPrState();
|
||||
await sendToProject({ name: "project.pr_sync.result", result });
|
||||
await sendToProject({ name: "repository.pr_sync.result", result });
|
||||
continue;
|
||||
}
|
||||
await handlePrSyncControl(c, msg); // force/stop/update-interval
|
||||
|
|
@ -338,10 +338,10 @@ run: async (c) => {
|
|||
run: async (c) => {
|
||||
const intervalMs = 5_000;
|
||||
while (true) {
|
||||
const msg = await c.queue.next("project.branch_sync.command", { timeout: intervalMs });
|
||||
const msg = await c.queue.next("repository.branch_sync.command", { timeout: intervalMs });
|
||||
if (!msg) {
|
||||
const result = await pollBranchState();
|
||||
await sendToProject({ name: "project.branch_sync.result", result });
|
||||
await sendToProject({ name: "repository.branch_sync.result", result });
|
||||
continue;
|
||||
}
|
||||
await handleBranchSyncControl(c, msg);
|
||||
|
|
@ -368,7 +368,7 @@ run: async (c) => {
|
|||
|
||||
## Sandbox Provider Interface
|
||||
|
||||
Provider contract lives under `packages/backend/src/providers/provider-api` and is consumed by workspace/project/task actors.
|
||||
Provider contract lives under `packages/backend/src/providers/provider-api` and is consumed by organization/repository/task actors.
|
||||
|
||||
```ts
|
||||
interface SandboxProvider {
|
||||
|
|
@ -398,26 +398,26 @@ Initial providers:
|
|||
- Boots/ensures Sandbox Agent inside sandbox.
|
||||
- Returns endpoint/token for session operations.
|
||||
|
||||
## Command Surface (Workspace + Provider Aware)
|
||||
## Command Surface (Organization + Provider Aware)
|
||||
|
||||
1. `hf create ... --workspace <ws> --provider <worktree|daytona>`
|
||||
2. `hf switch --workspace <ws> [target]`
|
||||
3. `hf attach --workspace <ws> [task]`
|
||||
4. `hf list --workspace <ws>`
|
||||
5. `hf kill|archive|merge|push|sync --workspace <ws> ...`
|
||||
6. `hf workspace use <ws>` to set default workspace
|
||||
1. `hf create ... --organization <ws> --provider <worktree|daytona>`
|
||||
2. `hf switch --organization <ws> [target]`
|
||||
3. `hf attach --organization <ws> [task]`
|
||||
4. `hf list --organization <ws>`
|
||||
5. `hf kill|archive|merge|push|sync --organization <ws> ...`
|
||||
6. `hf organization use <ws>` to set default organization
|
||||
|
||||
List/TUI include provider and sandbox health metadata.
|
||||
|
||||
`--workspace` remains optional; omitted values use the standard resolution order.
|
||||
`--organization` 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):
|
||||
Tables (organization-scoped):
|
||||
|
||||
1. `workspaces`
|
||||
1. `organizations`
|
||||
2. `workspace_provider_profiles`
|
||||
3. `repos` (`workspace_id`, `repo_id`, ...)
|
||||
4. `branches` (`workspace_id`, `repo_id`, ...)
|
||||
|
|
@ -433,10 +433,10 @@ Migration approach: one-way migration from existing schema during TS backend boo
|
|||
|
||||
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.
|
||||
3. OpenTUI subscribes to repository streams from organization-scoped repository actors.
|
||||
4. Organization is required context on all backend mutation requests.
|
||||
|
||||
CLI/TUI are responsible for resolving workspace context before calling backend mutations.
|
||||
CLI/TUI are responsible for resolving organization context before calling backend mutations.
|
||||
|
||||
## CLI + TUI Packaging
|
||||
|
||||
|
|
@ -451,10 +451,10 @@ The package still calls the same backend API and shares contracts from `packages
|
|||
|
||||
## Implementation Phases
|
||||
|
||||
## Phase 0: Contracts and Workspace Spec
|
||||
## Phase 0: Contracts and Organization Spec
|
||||
|
||||
1. Freeze workspace model, provider contract, and actor ownership map.
|
||||
2. Freeze command flags for workspace + provider selection.
|
||||
1. Freeze organization model, provider contract, and actor ownership map.
|
||||
2. Freeze command flags for organization + provider selection.
|
||||
3. Define Drizzle schema draft and migration plan.
|
||||
|
||||
Exit criteria:
|
||||
|
|
@ -462,7 +462,7 @@ Exit criteria:
|
|||
|
||||
## Phase 1: TypeScript Monorepo Bootstrap
|
||||
|
||||
1. Add `pnpm` workspace + Turborepo pipeline.
|
||||
1. Add `pnpm` organization + Turborepo pipeline.
|
||||
2. Create `shared`, `backend`, and `cli` packages (with TUI integrated into CLI).
|
||||
3. Add strict TypeScript config and CI checks.
|
||||
|
||||
|
|
@ -473,10 +473,10 @@ Exit criteria:
|
|||
|
||||
1. Wire local RivetKit dependency from `../rivet`.
|
||||
2. Add SQLite + Drizzle migrations and query layer.
|
||||
3. Implement actor registry with workspace-prefixed keys.
|
||||
3. Implement actor registry with organization-prefixed keys.
|
||||
|
||||
Exit criteria:
|
||||
- Backend boot + workspace actor health checks pass.
|
||||
- Backend boot + organization actor health checks pass.
|
||||
|
||||
## Phase 3: Provider Layer in Backend
|
||||
|
||||
|
|
@ -487,9 +487,9 @@ Exit criteria:
|
|||
Exit criteria:
|
||||
- `create/list/switch/attach/push/sync/kill` pass on worktree provider.
|
||||
|
||||
## Phase 4: Workspace/Task Lifecycle
|
||||
## Phase 4: Organization/Task Lifecycle
|
||||
|
||||
1. Implement workspace coordinator flows.
|
||||
1. Implement organization coordinator flows.
|
||||
2. Implement TaskActor full lifecycle + post-idle automation.
|
||||
3. Implement history events and PR/CI/review change tracking.
|
||||
|
||||
|
|
@ -509,7 +509,7 @@ Exit criteria:
|
|||
|
||||
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.
|
||||
3. Add organization switcher UX and provider/sandbox indicators.
|
||||
|
||||
Exit criteria:
|
||||
- TUI parity and responsive streaming updates.
|
||||
|
|
@ -534,7 +534,7 @@ Exit criteria:
|
|||
|
||||
2. Integration tests
|
||||
- backend + sqlite + provider fakes
|
||||
- workspace isolation boundaries
|
||||
- organization isolation boundaries
|
||||
- session recovery and restart handling
|
||||
|
||||
3. E2E tests
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue