Code structure
This guide explains where behavior belongs and how to follow it through the repository. Use development.md for setup and checks, and AGENTS.md for service and security boundaries.
Start with the deployment boundary
apps/
backend/
cloud_agent/ Control plane and its HTTP APIs
cloud_agent_host/ Host execution and retained sandbox management
cloud_agent_shared/ Contracts and algorithms shipped in both images
frontend/ Next.js browser UI and backend-for-frontend routes
gateway_contracts/ Gateway HTTP contracts and control-plane OpenAPI
migrations/ Agent-owned database schema, managed by Alembic
deploy/ Image builds and deployment entry points
scripts/ Development, qualification, and release tooling
tests/ Backend behavior, integration, and boundary checks
docs/ Maintained guides and dated design evidence
The control plane and host are independently deployed implementations. Neither imports the other. Shared code provides the facts and contracts they agree on; it imports neither implementation. Gateway integration uses HTTP contracts. The agent database and Gateway database remain separate.
Follow a control-plane request
flowchart TD
App[app.py: listener and route assembly] --> API[api/: HTTP adapters]
API --> Flows[application/ and services: orchestration]
API --> Ports[ports/: capability contracts]
Flows --> Ports
Flows --> Domain[domain/: rules and vocabulary]
Bootstrap[bootstrap/: resource and lifecycle assembly] --> Workers[workers/: background loops]
Workers --> Flows
Bootstrap --> Storage[storage/: Postgres implementations]
Storage --> Ports
Storage --> Domain
app.py mounts the owner/admin API and the separate MCP-only listener. It
installs shared HTTP response and exception policies. bootstrap/lifespan.py
constructs the resources and starts and stops background work; route modules
do not own service startup or shutdown.
Directory or module |
Owns |
Put a change here when |
|---|---|---|
|
HTTP parsing, dependencies, authorization entry points, response mapping |
The request or response behavior changes |
|
Pydantic request, response, and host/worker wire models |
A transport field or validation rule changes |
|
Admission, follow-ups, Fork, delivery, reconciliation, and other flows |
A use case coordinates several capabilities |
|
Execution state, request identity, and business vocabulary |
A rule is independent of persistence and HTTP |
|
Narrow typed capabilities |
A caller needs a new operation from an adapter |
|
Construction of Postgres repository capabilities |
A storage capability is wired into the service |
|
SQL and transaction/fencing behavior |
A durable query or mutation changes |
|
Scheduled work and recovery loops |
Work continues independently of a request |
|
Resources and lifecycle |
A component must be constructed, started, or closed |
|
MCP hosting, transport, policy, and process-local runtime |
Protocol or upstream session behavior changes |
|
Goal orchestration and retry policy |
Goal scheduling or progress policy changes |
|
External provider implementations |
A provider’s integration behavior changes |
The storage assembly exposes capabilities such as store.host_pool and
store.pending_messages. Callers type against the capabilities they use. They
do not import Postgres repositories or reach through the assembly to its pool.
Application flows may use the existing FastAPI exception contracts; moving
files does not imply those interfaces have become framework-independent.
MCP session ownership lives in mcp/runtime.py: lazy host construction,
fenced session reaping, maintenance, and closing. Both the relay’s handlers
and bootstrap call that runtime directly. Eager send-now handoff task retention
and cancellation live in application/send_now.py; the durable delivery rows
and recovery worker still own crash recovery.
API schemas are organized by domain
Import public models from cloud_agent.schemas. Its __init__.py explicitly
exports them; implementations use direct imports between domain modules rather
than importing the facade back into themselves.
Modules |
Models for |
|---|---|
|
Tasks, sessions, queues, questions, and goals |
|
Event streams, measurements, files, terminals, and Git views |
|
Worker requests, enrollment, heartbeats, and admin host controls |
|
Archive settings, admin audit, and advertised configuration |
|
Source control, MCP selection, identity, and user preferences |
|
Shared bounds for host and worker reports |
Keep model names and serialized behavior stable during structural refactors. Cross-domain annotations must resolve immediately after import. Intentional wire changes require the contract update described in the developer guide.
Follow a host execution
runner.py owns claims, attempt leases, turn execution, heartbeats, and draining.
claimed_job.py defines claim payloads and lease errors;
control_plane_client.py owns attempt-scoped worker HTTP calls, request
deadlines, and event replay. The runner explicitly re-exports their existing
public names and keeps client construction at its orchestration boundary.
chat_sandbox_models.py holds retained-container specs, inspection/status
values, ownership labels, and identity bounds. Group bridges, relay membership,
Kata guest route synchronization, and network proof/release live in the composed
chat_sandbox_network.py component. It consumes a narrow container protocol;
exact container identity, bounded exec, and fail-stop operations stay with the
manager. Existing manager network entry points delegate to that owner. Network
snapshots remain scoped to one operation, and operational log names are stable.
chat_sandbox.py manages retained groups and their members; sandbox.py owns the container/process
boundary. The Sandbox Manager and session supervisor coordinate native
sessions and workspace operations. The supervisor’s metadata lock protects
in-memory ownership only. Stop, orphan recovery, and archive deletion reserve
one group’s lifecycle before Docker or marker I/O, then revalidate its group,
member, container, and lifecycle identities before accepting the result. Other
groups remain available; failed checks release their temporary reservation,
while durable archive and native-flush barriers remain in force. Public sandbox model imports through
chat_sandbox continue to work.
The runtime adapters are a package under cloud_agent_host/runtimes/:
Module |
Responsibility |
|---|---|
|
Adapter contracts, capabilities, MCP configuration, and runtime errors |
|
Normalized event vocabulary and bounded payload helpers |
|
Partial-reply preview batching |
|
One CLI dialect’s commands and event parsing |
|
The generic line-oriented adapter |
|
Adapter lookup and construction |
Existing callers use cloud_agent_host.runtimes; the package explicitly
exports its public API. Runtime discovery facts live in the immutable
cloud_agent_shared/runtime_catalog.py, so the control plane advertises runtime
IDs, MCP support, and reasoning efforts without loading host adapters. Runtime
version pins remain in cloud_agent_shared/shared_protocol.py and image files.
Follow a browser action
Next.js route files live under apps/frontend/src/app/. Shared feature UI lives
under components/features/, reusable presentation components under
components/, and browser utilities and API clients under lib/. Server-only
integrations belong in the existing server modules; a browser component must
not pull server credentials into its import graph.
lib/api/agents.ts is the explicit public API facade. It delegates to focused
modules under lib/api/agents/: jobs, threads, sessions, goals, configuration,
integrations, resource and usage reads, workspace files, terminals, and event
streams. Shared create/Fork idempotency response handling stays private to that
package. Keep endpoint paths, retries, credentials, cursor handling, and
notifications with their owning operation.
components/features/agents/JobDetail.tsx composes the job page. Its extracted
implementation lives under job-detail/:
Module |
Responsibility |
|---|---|
|
Page header and conversation actions |
|
Transcript projection and navigation |
|
Message input and composer settings |
|
Outcome, publication, and Git interaction |
|
Workspace/inspector rendering and lazy loading |
|
Panel selection, focus, resizing, and retained panel state |
|
Turn navigation, transcript scrolling, and reading position |
|
Stop, Fork, and restore actions with request guards |
Keep state with the concern that owns it. Retained panels preserve terminals, file previews, and drafts while hidden; scope changes must reset the relevant state. Keep hooks’ dependencies explicit and preserve lazy loading when extracting components.
Add a feature without losing the structure
Identify the service and concern that owns the behavior using the maps above.
Add or update its domain rule, wire model, and port only where the behavior requires them. Implement durable operations inside storage.
Put orchestration in an application flow or owning service, then call it from the HTTP adapter or worker. Wire new resources through bootstrap.
Add public facade exports deliberately. Import implementation modules directly within a package to keep its dependency graph clear.
Exercise observable behavior and affected boundaries. For structural refactors, compare contracts and reuse existing behavioral tests.
Run the relevant complete gates and update the maintained guide for changed ownership, commands, or behavior.
Backend architecture checks enforce service-image independence, API import
direction, domain/port independence, and repository isolation. Backend imports
must use the installed package names (cloud_agent, cloud_agent_host, and
cloud_agent_shared), rather than the checkout namespace apps.backend.
The host image flattens these packages, so checkout-prefixed imports can work
locally and fail after deployment; the guards reject them in all three packages.
The import scanners include relative imports, imports inside functions, and
TYPE_CHECKING blocks. Backend behavior tests remain under tests/; frontend
tests remain alongside the feature or utility they exercise.