# Workspace frontend boundaries

> Canonical path: `specs/web/workspace-boundaries.md`
> Status: active
> Scope: `web/src/agentteam/pages`, `web/src/agentteam/workspace`, and workspace domain migration guardrails.

## Contract

AgentTeam Web keeps the top-level frontend split stable:

- `web/src/entries/*` and `web/src/runtime/*` own Browser/Desktop bootstrap and host adapters as defined by [Web runtime and host boundaries](./runtime-host-boundaries.md).
- `web/src/agentteam/pages/*` owns app-level pages, routing, and shell composition.
- `web/src/agentteam/pages/WorkspaceShell.tsx` may assemble workspace surfaces, bootstrap data, and connect realtime streams.
- `web/src/agentteam/workspace/*` owns workspace product domains after a user enters a workspace.
- `web/src/agentteam/components/ui/*` remains the source of truth for shared UI primitives.

Workspace pages consume the common runtime contract and server API. They do not import Desktop adapters, inspect Wails/localhost/user-agent signals to select business behavior, or call `/api/internal/*`.

The `workspace` root is legacy migration debt, not the default destination for new files. New and migrated workspace code should move toward domain folders with explicit public entries.

## Initial domains

The first stable workspace domains are:

- `workspace/shared/` for cross-domain workspace helpers, query/cache utilities, layout helpers, permissions helpers, and small primitives that are not tied to one product domain.
- `workspace/conversation/` for channel, DM, thread, message timeline, message row, reply-thread panel, composer, and conversation-specific state.
- `workspace/tasks/` for task board, task detail, task discussion, and task-specific query/cache helpers.

Future domains should follow the same pattern when those areas are migrated, for example `agents/`, `machines/`, `apps/`, `settings/`, `triggers/`, `search/`, or `sidebar/`.

## Public and private imports

Each managed domain should expose narrow stable entry points from its root.
Files below domain subdirectories are private to that domain unless the domain
README explicitly says otherwise. The conversation and task domains do not
expose broad `index.ts` barrels because those barrels collapse route-level
lazy-loading boundaries.

Cross-domain imports should prefer one of these forms:

```ts
import { somethingShared } from "@/agentteam/workspace/shared"
import { taskStatusLabel } from "@/agentteam/workspace/tasks/status"
```

Avoid importing another domain's private implementation path:

```ts
import { buildTaskRows } from "@/agentteam/workspace/tasks/state/buildTaskRows"
```

If a helper is needed by more than one domain, first decide whether it is genuinely shared. Move it to `shared/` only when it has a stable cross-domain meaning; otherwise expose a small public function from the owning domain.

## Guardrail

`guardrails/web/workspace-boundaries.sh` invokes `web/scripts/check-workspace-boundaries.mjs` and enforces only low-risk rules that are safe at this stage:

1. workspace source files must not import `src/agentteam/pages/*`;
2. new root-level workspace `.ts` / `.tsx` files are blocked by `web/scripts/workspace-root-files-allowlist.json`;
3. migrated managed domains must not import each other's private internals;
4. `workspace/shared` must not depend on feature domains.

The root-file allowlist is a migration ratchet. Removing files from the workspace root is always allowed; adding new root files should be temporary and intentional.

This guardrail is intentionally conservative. Tighten it after more root files move into domain folders.
