679 lines
16 KiB
Markdown
679 lines
16 KiB
Markdown
# Zopu Work OS — Technical Architecture
|
|
|
|
> **Related:** `agent-context.md` defines agent rules; `dev-loop.md` defines orchestration; `glossary.md` defines terms.
|
|
|
|
> **Status:** Working technical source of truth
|
|
> **Audience:** engineers and implementation agents
|
|
> **Read after:** `product.md`
|
|
> **Principle:** durable intent/state is separate from disposable execution.
|
|
|
|
## 1. System topology
|
|
|
|
```text
|
|
Web / desktop / mobile
|
|
│ Convex queries, mutations, storage
|
|
▼
|
|
Convex application backend
|
|
├── authentication and tenancy
|
|
├── normalized product data
|
|
├── conversation turn queue
|
|
└── reactive client projections
|
|
│ durable Workflow steps + service-authenticated dispatch
|
|
▼
|
|
Private agent backend
|
|
├── FLUE product agents and typed tools
|
|
├── AgentOS execution environments
|
|
├── Codex implementation harness
|
|
└── canonical events/results returned to Convex
|
|
│ optional attached full sandbox
|
|
▼
|
|
Cube/E2B-compatible runtime (later)
|
|
```
|
|
|
|
Clients MUST communicate only with Convex. FLUE and future Rivet/AgentOS services are private workers: Convex admits durable commands, invokes the worker, and stores the product-facing result before clients observe it.
|
|
|
|
### Ownership
|
|
|
|
| Layer | Owns |
|
|
| --- | --- |
|
|
| Convex | authentication, normalized product records, command admission, reactive reads |
|
|
| Convex Workflow | durable sequencing, retries, cancellation, scheduling, and completion callbacks |
|
|
| Agent backend | private programmable agents and execution adapters |
|
|
| Rivet Engine + runners | placement, routing, sleep/wake, and execution ownership for AgentOS workspaces |
|
|
| Harness | bounded coding/tool loop |
|
|
| Sandbox/runtime | filesystem, processes, network, isolation |
|
|
| Git | source revision history |
|
|
| Artifact store | durable outputs/evidence |
|
|
| External systems | collaboration, delivery, monitoring |
|
|
|
|
No client, harness, sandbox, or FLUE process owns product state.
|
|
|
|
### Slice 1 relational core
|
|
|
|
```text
|
|
organizations ──< organizationMembers
|
|
organizations ──< projects ──< projectContextDocuments
|
|
organizations ──1 conversations ──< conversationTurns
|
|
conversationTurns ──< conversationMessages ──< conversationAttachments
|
|
projects ──< signals ──< signalConstraints
|
|
signals ──< signalSources >── conversationMessages
|
|
projects ──< works
|
|
signals ──< signalWorkAttachments >── works
|
|
works ──< workEvents
|
|
```
|
|
|
|
Convex mutations provide atomic transactions and optimistic serializability. Foreign-key integrity and uniqueness are enforced in the owning mutations; composite indexes back every identity and relation lookup. Flue's adapter tables remain isolated infrastructure persistence and are not product-domain relations.
|
|
|
|
## 2. Domain boundaries
|
|
|
|
Recommended packages:
|
|
|
|
```text
|
|
packages/
|
|
├── signals/
|
|
├── work/
|
|
├── design/
|
|
├── planning/
|
|
├── kits/
|
|
├── resolver/
|
|
├── verification/
|
|
├── artifacts/
|
|
├── results/
|
|
├── knowledge/
|
|
├── runtimes/
|
|
├── harnesses/
|
|
└── integrations/
|
|
```
|
|
|
|
Each domain SHOULD separate:
|
|
|
|
```text
|
|
domain/ pure state, schemas, invariants
|
|
application/ use cases and orchestration
|
|
ports/ Effect services
|
|
adapters/ infrastructure implementations
|
|
```
|
|
|
|
Avoid package proliferation in v0; logical boundaries may begin as folders.
|
|
|
|
## 3. Core records
|
|
|
|
Minimal durable model:
|
|
|
|
```ts
|
|
type Id = string;
|
|
|
|
interface Message {
|
|
id: Id;
|
|
projectId: Id;
|
|
content: string;
|
|
createdAt: number;
|
|
}
|
|
|
|
interface Signal {
|
|
id: Id;
|
|
projectId: Id;
|
|
sourceType: string;
|
|
sourceId: string;
|
|
sourcePayloadRef?: string;
|
|
summary: string;
|
|
fingerprint: string;
|
|
status: "candidate" | "accepted" | "dismissed";
|
|
}
|
|
|
|
interface Work {
|
|
id: Id;
|
|
projectId: Id;
|
|
title: string;
|
|
objective: string;
|
|
risk: "low" | "medium" | "high";
|
|
status: WorkStatus;
|
|
definitionVersion?: number;
|
|
designVersion?: number;
|
|
createdAt: number;
|
|
updatedAt: number;
|
|
}
|
|
|
|
interface Step {
|
|
id: Id;
|
|
workId: Id;
|
|
sliceId?: Id;
|
|
kind: "design" | "implement" | "verify" | "integrate" | "publish" | "observe";
|
|
objective: string;
|
|
dependsOn: readonly Id[];
|
|
status: StepStatus;
|
|
}
|
|
|
|
interface Run {
|
|
id: Id;
|
|
workId: Id;
|
|
stepId: Id;
|
|
kitVersion: string;
|
|
status: RunStatus;
|
|
}
|
|
|
|
interface Attempt {
|
|
id: Id;
|
|
runId: Id;
|
|
number: number;
|
|
harness: string;
|
|
runtime: string;
|
|
sourceRevision: string;
|
|
status: AttemptStatus;
|
|
startedAt?: number;
|
|
endedAt?: number;
|
|
}
|
|
|
|
interface Artifact {
|
|
id: Id;
|
|
workId: Id;
|
|
stepId?: Id;
|
|
runId?: Id;
|
|
attemptId?: Id;
|
|
type: string;
|
|
uri?: string;
|
|
contentHash?: string;
|
|
sourceRevision?: string;
|
|
environmentId?: string;
|
|
metadata: unknown;
|
|
}
|
|
|
|
interface Question {
|
|
id: Id;
|
|
workId: Id;
|
|
stepId?: Id;
|
|
attemptId?: Id;
|
|
prompt: string;
|
|
recommendation?: string;
|
|
alternatives: readonly string[];
|
|
status: "open" | "answered" | "withdrawn";
|
|
answer?: string;
|
|
}
|
|
```
|
|
|
|
All external/model payloads MUST be decoded with schemas at boundaries.
|
|
|
|
## 4. Work state machine
|
|
|
|
```text
|
|
Proposed
|
|
→ Defining
|
|
→ AwaitingDefinitionApproval
|
|
→ Designing
|
|
→ AwaitingDesignApproval
|
|
→ Ready
|
|
→ ExecutingSlice
|
|
→ VerifyingSlice
|
|
→ AwaitingSliceReview
|
|
→ IntegratedVerification
|
|
→ Review
|
|
→ Releasing
|
|
→ Observing
|
|
→ Completed
|
|
```
|
|
|
|
Side/terminal states:
|
|
|
|
```text
|
|
NeedsInput | Blocked | Replanning | Failed | Cancelled
|
|
```
|
|
|
|
Transitions require explicit commands plus evidence. State MUST NOT be inferred from the latest text message.
|
|
|
|
## 5. Actor model
|
|
|
|
Start small.
|
|
|
|
### ProjectActor
|
|
|
|
Owns:
|
|
|
|
- project configuration;
|
|
- repository/runtime policies;
|
|
- active Work index;
|
|
- integration endpoints;
|
|
- project-level Signal routing.
|
|
|
|
### WorkActor
|
|
|
|
Initial central aggregate:
|
|
|
|
- Work Definition and versions;
|
|
- Design Packet and versions;
|
|
- slice/step graph;
|
|
- Resolver state;
|
|
- approvals/questions;
|
|
- artifact references;
|
|
- result.
|
|
|
|
It serializes lifecycle transitions and commands.
|
|
|
|
### AttemptActor
|
|
|
|
Owns one execution attempt:
|
|
|
|
- runtime lease/sandbox ID;
|
|
- harness session;
|
|
- scoped credentials;
|
|
- event stream/checkpoints;
|
|
- cancellation;
|
|
- attempt timeout;
|
|
- normalized outcome.
|
|
|
|
### VerificationActor
|
|
|
|
Split from WorkActor after v0 verification is stable. Owns plan, checks, evidence, verdict.
|
|
|
|
### IntegrationActor
|
|
|
|
Added when multiple slices/branches exist. Owns branch composition, conflicts, integrated revision, integrated checks.
|
|
|
|
### ResultActor
|
|
|
|
Added after delivery observation exists. Owns rollout observation, original success signals, final outcome, learning proposals.
|
|
|
|
Do not create an actor per document or tool call. Create actors for durable identity, serialized ownership, independent failure/recovery, or timers.
|
|
|
|
## 6. Commands, events, and idempotency
|
|
|
|
Use command/event vocabulary rather than mutable agent prose.
|
|
|
|
Example commands:
|
|
|
|
```text
|
|
ProcessMessage
|
|
AcceptSignal
|
|
CreateWork
|
|
ApproveDefinition
|
|
ApproveDesign
|
|
StartNextSlice
|
|
RecordHarnessEvent
|
|
CompleteAttempt
|
|
StartVerification
|
|
RecordVerificationCheck
|
|
CreateRepairAttempt
|
|
PublishPullRequest
|
|
RecordHumanDecision
|
|
CompleteWork
|
|
```
|
|
|
|
Example events:
|
|
|
|
```text
|
|
SignalCreated
|
|
SignalAttached
|
|
WorkProposed
|
|
DefinitionGenerated
|
|
DefinitionApproved
|
|
DesignGenerated
|
|
DesignApproved
|
|
SliceStarted
|
|
AttemptStarted
|
|
AttemptCompleted
|
|
VerificationPassed
|
|
VerificationFailed
|
|
QuestionOpened
|
|
QuestionAnswered
|
|
PullRequestCreated
|
|
WorkCompleted
|
|
```
|
|
|
|
Every side-effecting command MUST include an idempotency key. Suggested key:
|
|
|
|
```text
|
|
<workId>:<commandType>:<logicalVersion>
|
|
```
|
|
|
|
External artifact creation stores provider ID before transition completion to prevent duplicate PRs/deployments.
|
|
|
|
## 7. Effect service boundaries
|
|
|
|
Keep domain/application code provider-neutral.
|
|
|
|
```ts
|
|
interface HarnessRuntime {
|
|
open(input: OpenHarnessInput): Effect.Effect<HarnessSession, HarnessError>;
|
|
prompt(id: string, content: string): Effect.Effect<void, HarnessError>;
|
|
events(id: string): Stream.Stream<HarnessEvent, HarnessError>;
|
|
approve(input: PermissionDecision): Effect.Effect<void, HarnessError>;
|
|
abort(id: string): Effect.Effect<void, HarnessError>;
|
|
close(id: string): Effect.Effect<void, HarnessError>;
|
|
}
|
|
|
|
interface SandboxRuntime {
|
|
create(spec: SandboxSpec): Effect.Effect<SandboxLease, SandboxError>;
|
|
exec(
|
|
lease: SandboxLease,
|
|
cmd: Command
|
|
): Effect.Effect<CommandResult, SandboxError>;
|
|
readFile(
|
|
lease: SandboxLease,
|
|
path: string
|
|
): Effect.Effect<Uint8Array, SandboxError>;
|
|
writeFile(
|
|
lease: SandboxLease,
|
|
path: string,
|
|
body: Uint8Array
|
|
): Effect.Effect<void, SandboxError>;
|
|
pause(lease: SandboxLease): Effect.Effect<void, SandboxError>;
|
|
resume(id: string): Effect.Effect<SandboxLease, SandboxError>;
|
|
terminate(lease: SandboxLease): Effect.Effect<void, SandboxError>;
|
|
}
|
|
|
|
interface SourceControl {
|
|
prepareWorktree(input: WorktreeInput): Effect.Effect<Worktree, GitError>;
|
|
diff(worktree: Worktree): Effect.Effect<DiffArtifact, GitError>;
|
|
commit(input: CommitInput): Effect.Effect<CommitArtifact, GitError>;
|
|
push(input: PushInput): Effect.Effect<BranchArtifact, GitError>;
|
|
createPullRequest(
|
|
input: PullRequestInput
|
|
): Effect.Effect<PullRequestArtifact, GitError>;
|
|
}
|
|
|
|
interface VerificationRuntime {
|
|
execute(
|
|
plan: VerificationPlan,
|
|
env: EnvironmentRef
|
|
): Effect.Effect<VerificationResult, VerificationError>;
|
|
}
|
|
```
|
|
|
|
Also define:
|
|
|
|
```text
|
|
ArtifactStore | SecretBroker | EventJournal | PreviewRuntime | RuntimePolicy
|
|
```
|
|
|
|
Use `Layer` for adapters, `Scope` for leases/processes, `Stream` for events, `Schedule` for bounded retries, and supervised fibers for long-running consumers. Pin Effect version and isolate beta API churn.
|
|
|
|
## 8. FLUE responsibilities
|
|
|
|
Use FLUE for domain-specific agents/workflows:
|
|
|
|
- conversation response and Signal proposal;
|
|
- Work Definition compiler;
|
|
- impact analysis;
|
|
- architecture/program design;
|
|
- vertical-slice planning;
|
|
- Resolver decision support;
|
|
- verification-plan generation;
|
|
- maintainability review;
|
|
- result/learning synthesis.
|
|
|
|
FLUE output MUST be typed proposals/commands, validated by application policy.
|
|
|
|
FLUE MUST NOT directly:
|
|
|
|
- mutate arbitrary database tables;
|
|
- bypass actor lifecycle;
|
|
- grant itself tools;
|
|
- merge/deploy outside policy;
|
|
- mark Work complete without evidence.
|
|
|
|
## 9. Harness strategy
|
|
|
|
Harness is replaceable:
|
|
|
|
```text
|
|
HarnessRuntime
|
|
├── OmpHarnessLive
|
|
├── OpenCodeHarnessLive
|
|
├── CodexHarnessLive
|
|
├── PiHarnessLive
|
|
└── FlueHarnessLive
|
|
```
|
|
|
|
v0 selects one harness. Prefer mature coding harnesses for repository exploration/edit/test loops; use custom FLUE agents for product-specific reasoning.
|
|
|
|
Zopu owns Work, branches, worktrees, budgets, approvals, artifacts, and completion. Harness owns one bounded implementation loop.
|
|
|
|
## 10. Runtime strategy
|
|
|
|
### Convex orchestration
|
|
|
|
Slice 5 uses the Convex Workflow component as the durable product orchestration layer. Workflow steps call private agent-backend actions, while all user-visible state, events, artifacts, idempotency keys, and cancellation remain canonical in Convex.
|
|
|
|
### CubeSandbox
|
|
|
|
Best for full Linux execution:
|
|
|
|
- native binaries;
|
|
- Bun/Node/Python;
|
|
- browsers;
|
|
- databases/services;
|
|
- project builds/tests;
|
|
- pause/resume;
|
|
- strong isolation.
|
|
|
|
Use E2B-compatible SDK behind `SandboxRuntime`. OMP runs as a process inside the Cube microVM.
|
|
|
|
### AgentOS
|
|
|
|
Best for:
|
|
|
|
- lightweight durable agent environments;
|
|
- ACP-integrated software;
|
|
- actor-adjacent orchestration;
|
|
- context/files/networking that fit runtime limits.
|
|
|
|
Slice 5 starts here with one Codex-backed AgentOS actor and one authenticated repository checkout per project. Convex Workflow owns product orchestration; Rivet Engine coordinates placement while a normal runner executes the actor. Use an attached full sandbox through the E2B-compatible boundary when native/heavy tooling is needed.
|
|
|
|
### Persistent project machine
|
|
|
|
Later optimization for long-lived caches, large repositories, and developer-customized environments. Use Git worktrees per active Work. Do not make it the only isolation boundary.
|
|
|
|
### Runtime selection
|
|
|
|
The Resolver requests capabilities:
|
|
|
|
```text
|
|
writable repo, Bun, browser, PostgreSQL, 8 GB RAM, network policy
|
|
```
|
|
|
|
`RuntimePolicy` chooses provider. Product logic never branches on Cube/AgentOS directly.
|
|
|
|
## 11. Repository isolation
|
|
|
|
Initial safe model:
|
|
|
|
```text
|
|
one project repository mirror
|
|
one Git worktree per active Work/slice
|
|
one mutating attempt per worktree
|
|
```
|
|
|
|
Rules:
|
|
|
|
- attempts receive scoped worktrees;
|
|
- parallel mutating attempts use separate branches;
|
|
- credentials are short-lived and repository-scoped;
|
|
- host home directories are never mounted;
|
|
- model credentials are run-scoped;
|
|
- untrusted code runs in sandbox;
|
|
- output commits record base and candidate SHA.
|
|
|
|
## 12. Planning and design artifacts
|
|
|
|
Required for standard work:
|
|
|
|
```text
|
|
WorkDefinition
|
|
ImpactMap
|
|
DesignPacket
|
|
VerticalSlicePlan
|
|
VerificationPlan
|
|
```
|
|
|
|
Program design SHOULD include:
|
|
|
|
- expected file-tree delta;
|
|
- expected call-flow delta;
|
|
- key types/signatures;
|
|
- dependency direction;
|
|
- invariants;
|
|
- security/data boundaries;
|
|
- known deviations.
|
|
|
|
The verifier compares candidate code against this design, but metrics are evidence, not absolute truth.
|
|
|
|
## 13. Verification architecture
|
|
|
|
Verification layers:
|
|
|
|
```text
|
|
Static
|
|
├── format/lint/typecheck
|
|
├── dependency policy
|
|
├── secret scan
|
|
└── static security
|
|
|
|
Behavior
|
|
├── unit
|
|
├── integration
|
|
├── contract
|
|
└── property tests where useful
|
|
|
|
Product
|
|
├── browser/user flow
|
|
├── screenshots/video
|
|
├── accessibility
|
|
└── visual checks
|
|
|
|
Operational
|
|
├── build/start/health
|
|
├── migration/rollback
|
|
├── logs
|
|
└── resource limits
|
|
|
|
Design
|
|
├── expected vs actual files/interfaces
|
|
├── dependency graph delta
|
|
├── design deviations
|
|
└── maintainability review
|
|
```
|
|
|
|
A `VerificationResult` MUST bind checks to candidate commit and environment.
|
|
|
|
Repair loop:
|
|
|
|
```text
|
|
failure evidence → bounded repair attempt → clean verification rerun
|
|
```
|
|
|
|
Tests added by the implementation SHOULD fail on the base revision and pass on the candidate when practical.
|
|
|
|
## 14. Delivery and integration
|
|
|
|
Publishing order:
|
|
|
|
```text
|
|
slice checks pass
|
|
→ integrated candidate created
|
|
→ impacted checks on integrated SHA
|
|
→ commit/push
|
|
→ PR
|
|
→ review package
|
|
```
|
|
|
|
Never create a “verified PR” from a different SHA than the verified candidate.
|
|
|
|
Review package:
|
|
|
|
- original intent;
|
|
- approved definition/design;
|
|
- slice narrative;
|
|
- meaningful diffs;
|
|
- screenshots/video;
|
|
- verification evidence;
|
|
- deviations/risks;
|
|
- exact commit/PR.
|
|
|
|
Manual merge remains policy in v0.
|
|
|
|
## 15. Preview and release
|
|
|
|
Preview is an artifact, not an open random port. `PreviewRuntime` may use:
|
|
|
|
- sandbox-exposed app;
|
|
- agentOS Apps for compatible generated HTTP apps;
|
|
- external staging/deployment.
|
|
|
|
Production release requires explicit policy, rollout plan, health signals, and rollback trigger.
|
|
|
|
## 16. Security baseline
|
|
|
|
- private control-plane endpoints;
|
|
- authenticated Cube/Rivet APIs;
|
|
- scoped runtime tokens;
|
|
- no long-lived model/Git secrets in workspace files;
|
|
- network egress policy;
|
|
- artifact access authorization;
|
|
- immutable audit trail for approvals;
|
|
- tool allowlist per Kit;
|
|
- destructive tools denied by default;
|
|
- merge/deploy human-gated initially;
|
|
- cleanup of terminated sandboxes and credentials.
|
|
|
|
## 17. Observability
|
|
|
|
Record product-level events, not only infrastructure logs.
|
|
|
|
Required dimensions:
|
|
|
|
```text
|
|
projectId workId sliceId runId attemptId actorId
|
|
kitVersion harness runtime model baseSha candidateSha
|
|
```
|
|
|
|
Track:
|
|
|
|
- state-transition latency;
|
|
- attempt duration/outcome;
|
|
- retries/replans;
|
|
- verification checks;
|
|
- human wait time;
|
|
- token/compute cost;
|
|
- duplicate side effects;
|
|
- abandoned/stale Work;
|
|
- post-release failures.
|
|
|
|
Raw harness logs are retained as artifacts; UI consumes normalized events.
|
|
|
|
## 18. Initial deployment shape
|
|
|
|
```text
|
|
Web + API + Convex
|
|
│
|
|
▼
|
|
Bun/Effect daemon
|
|
│
|
|
▼
|
|
Rivet cluster/actors
|
|
│
|
|
├── FLUE agents/workflows
|
|
└── SandboxRuntime
|
|
└── CubeSandbox on dedicated/VDS host
|
|
└── OMP + repo + tests
|
|
```
|
|
|
|
Keep Cube control APIs private; expose only authorized preview paths. Rivet and execution daemon may share the VPS initially but remain separate deployable processes.
|
|
|
|
## 19. Technical acceptance for v0
|
|
|
|
The architecture is proven when one real repository supports:
|
|
|
|
```text
|
|
message → Signal → approved Work → approved Design Packet
|
|
→ one slice → isolated harness run → independent verification
|
|
→ verified commit → real PR → human response/resume
|
|
```
|
|
|
|
With:
|
|
|
|
- durable recovery;
|
|
- no duplicate Work/PR;
|
|
- bounded retries;
|
|
- exact evidence;
|
|
- cancellation;
|
|
- explicit terminal states.
|