# MeshX Service Boundaries

> Canonical path: `specs/architecture/meshx-service-boundaries.md`
> Status: living-spec
> Scope: MeshX service ownership, dependency direction, and server composition.
> Related specs: [`specs/architecture/unified-agentteam-runtime.md`](./unified-agentteam-runtime.md)

## 1. Purpose

MeshX services are split by product resource and shared lifecycle plane.
`internal/resource/server` composes the domain services it serves; there is no root
service facade.

Server composition must not grow into a business-logic facade. Resource behavior,
permission checks, repository lifecycle rules, AGS operations, activity
projection, and API error translation belong to the package that owns that
behavior.

## 2. Package ownership

```mermaid
flowchart TB
    Server["internal/resource/server"]
    Router["internal/router"]
    API["internal/api/{kb,memory,skills,automations,...}"]

    KB["internal/service/kb\nknowledge-base semantics"]
    Memory["internal/service/memory\nmemory semantics"]
    Skills["internal/service/skills\nskill semantics"]
    Automation["internal/service/automation\nautomation semantics"]
    AutomationRuntime["internal/service/automation/runtime\nautomation execution lifecycle"]
    AutomationBlob["internal/automation/blob\nlog + artifact payload storage"]
    AutomationDSL["internal/automation/dsl\ndefinition + validation contract"]
    ResourceRepos["internal/service/resource/repos\nshared repository lifecycle plane"]
    ResourceActivity["internal/service/resource/activity\nshared activity projection"]
    ResourceActivityStore["internal/store/resource/activity\nevents + projection checkpoints"]
    PersonalAccessTokenStore["internal/store/providertokens\nuser-held external provider tokens"]
    ResourceRolesStore["internal/store/resource/roles\nruntime Role catalog + assignments"]
    ResourceAccess["internal/service/resource/access\naccess-change + sync lease primitives"]
    AccessTokens["internal/service/repotokens\nsync-token lifecycle"]
    AGSBridge["internal/agsbridge\nembedded AGS trust + identity + requests"]
    AGSGitTransport["internal/agsbridge/gittransport\nprocess-local go-git transport"]
    KBGovernance["internal/kbgovernance\nKB Approval contract"]
    AGSRepo["internal/agsbridge/wiki\nwiki/publication port"]
    Stores["internal/store/{automations,kb,knowledgeqa,...}"]

    Server --> Skills
    Server --> API
    Server --> AGSBridge
    Server --> AGSGitTransport
    Server --> KBGovernance
    Router --> API
    API --> KB
    API --> Memory
    API --> Skills
    API --> Automation

    Server --> KB
    Server --> Memory
    Server --> Automation
    Server --> ResourceRepos
    Server --> ResourceActivity

    KB --> ResourceRepos
    KB --> KBGovernance
    Memory --> ResourceRepos
    Skills --> ResourceRepos
    Skills --> ResourceActivity
    ResourceActivity --> ResourceActivityStore
    KB --> PersonalAccessTokenStore
    Server --> PersonalAccessTokenStore
    Server --> ResourceRolesStore
    Automation --> ResourceRepos
    Automation --> AutomationRuntime
    Automation --> AutomationBlob
    Automation --> AutomationDSL
    KB --> ResourceAccess
    Memory --> ResourceAccess
    Skills --> ResourceAccess
    ResourceRepos --> AGSBridge
    AGSRepo --> ResourceRepos
    ResourceRepos --> Stores
    ResourceAccess --> Stores
    AccessTokens --> Stores
```

## 3. Boundary rules

### API ownership under `internal/api`

MeshX HTTP adapters, product route owners, DTOs, and DTO converters live under
`internal/api`. The retired MeshX transitional namespace must remain absent,
and `internal/api` must not import the retired MeshX namespace; runtime
assembly may depend on API owners, never the reverse.

### Composition in `internal/resource/server`

`internal/resource/server` owns resource-service composition:

- `resource_services.go`: construction of the KB, Memory, Automation, and
  personal-access-token services from their domain stores and options.

The process-to-resource dependency direction is fixed as
`internal/server → internal/meshxruntime → internal/resource/server → internal/router`.
Only `internal/meshxruntime` imports the resource server; domain owners never import
composition for convenience.

Server composition must not own:

- resource permissions, repository naming, repository lifecycle cleanup, AGS HTTP
  calls, sync-token semantics, activity event semantics, API response mapping,
  or user-facing business behavior;
- exported aliases or wrappers that re-create a root service facade;
- tests that freeze cross-domain facade behavior instead of testing the owning domain.

API handlers, router code, domain services, and tests import the owning domain
package directly; server-only construction stays in `internal/resource/server`.
No compatibility facade may recreate the retired transitional namespace.

### Resource domain packages

- `internal/service/kb` owns knowledge-base and source-repository behavior: KB/source
  permissions, KB storage settings, source mirroring, AGS wiki access, KB import
  and retrieval behavior, localized codebase/file source-repository label
  taxonomies, and KB-specific error mapping. Those labels are not part of the
  shared Memory preset.
- `internal/service/memory` owns memory resource behavior: memory repository templates,
  forks, deletion, permissions, activity, sync-token consumption, and
  memory-specific error mapping. It consumes locale, files, commit messages,
  and labels directly from the shared `presets` memory contract instead of
  introducing a MeshX pass-through package.
- `internal/service/skills` owns skill behavior: skill repository creation, imports,
  built-in presets, agent bindings, permission grants, activity, and skill sync
  leases.
- `internal/service/automation` owns automation behavior: automation definitions,
  source files, runtime orchestration, secrets, runner state, AGS publish paths,
  and automation-specific errors. It consumes the root Automation foundation
  packages directly instead of re-declaring their contracts.
- `internal/service/automation/runtime` owns the automation execution lifecycle:
  queue scheduling and reconciliation, runner leases, executor integration,
  repository-status work, and terminal state transitions.

`internal/automation/blob` owns automation log and artifact payload storage primitives,
including object-key construction, content hashing, the bounded
listing contract, and the filesystem implementation. It remains a separate
subpackage so the Automation service and runtime can share blob contracts
without introducing an Automation-to-runtime dependency cycle.

`internal/automation/dsl` owns the automation definition and validation contract,
including supported checkout and publication steps, environment
resolution, triggers, and validation reports. Both root Automation foundation
packages are dependency leaves; callers import these exact owners rather than
re-declaring their contracts.

Resource domains may depend on shared lifecycle packages when the shared package
expresses a lower-level lifecycle concept. They must not depend on server composition
for convenience aliases or cross-domain shortcuts.

### Shared lifecycle packages

`internal/service/resource/repos` owns AGS-backed resource repository lifecycle primitives:
repository identity/value objects, storage-scope/name resolution, availability
checks, canonical `resource_repositories` mapping helpers, lifecycle failure and
cleanup helpers, collaborator grant contracts, and repository sync-token
contracts. It must stay domain-agnostic and must not import KB, Memory, Skill,
Automation, or API packages.

`internal/service/automation`, `internal/service/kb`, `internal/service/memory`, and `internal/agsbridge/wiki`
must not re-declare the exported `internal/service/resource/repos` lifecycle owner
surface. Repository identity, actor, ensure/delete/access contracts,
storage-scope/name constants, name resolution and availability helpers,
lifecycle failure and cleanup helpers, and sync-token contracts are imported
from `internal/service/resource/repos` directly. `internal/service/memory` consumes those lifecycle
contracts directly while retaining only Memory-specific initialization, fork,
backup, history, and access request shapes. `internal/agsbridge/wiki` remains a narrow
wiki/publication port expressed in terms of the shared lifecycle contracts.
Local helpers that express Automation source/runtime semantics, KB
wiki/source-mirror/access-profile semantics, or Memory content semantics are
not affected. The duplicate-prevention surface is enumerated in
`guardrails/architecture/check-meshx-service-boundaries.sh`.

`internal/service/resource/activity` owns cross-resource activity projection and display
normalization. `internal/store/resource/activity` owns the persisted activity
events, latest-commit projection, projector checkpoints, and their bounded
query/update contracts. Resource domains consume that store owner directly;
each resource domain still owns when to emit events and how authorization for
those events is enforced.

`internal/service/resource/access` owns the domain-agnostic access-change outbox helper
and normalized short-lived repository sync-lease requests shared by KB, Memory,
and Skills. It must not import concrete KB, Memory, Skills, or Automation service
packages. Domains pass explicit repository full names and capabilities instead
of asking server composition for an implicit token policy.

`internal/service/repotokens` remains the separate owner of sync-token
issuance and lifecycle; issuing tokens is not a low-level access-request helper.

`internal/service/providertokens` owns user-held external provider credential
lifecycle, owner scoping, and plaintext encryption before persistence.
`internal/store/providertokens` owns the corresponding persistence records.
This store is not the owner of AgentTeam session or authentication tokens,
repository-scoped credentials, or API DTOs. Its persistence contract remains
workspace- and owner-scoped, and metadata lists stay bounded independently of
unrelated saved tokens.

`internal/store/resource/roles` owns resource runtime Role catalog, immutable
version and package-manifest, grant, agent assignment, realization, and operation
receipt persistence. Authorization policy remains in `internal/service/roles`, and API
handlers translate service values rather than exposing store projections. These
records are not interchangeable with organization membership roles, API DTOs,
or `internal/store/role/execution`, which owns only the Approval-driven Role
management execution projection.

`internal/kbgovernance` owns the transport-neutral KB Approval contract: the
canonical payload, publication, terminal-notification, and authority values
shared by MeshX KB behavior and AgentTeam Approval composition. It contains no KB or
Approval business implementation and must not depend on resource-server or
runtime composition packages.

`internal/identity/trusted` owns the AgentTeam-verified JWT identity value, trusted
header extraction, optional development mock fallback, token mapping, and request
context propagation used behind protected listeners. It must not import any
resource-server or runtime composition package. Resource owners may import only
this exact identity package, not its subpackages or other root internals.

`internal/agsbridge` owns trusted embedded-AGS context markers, conversion from
`trusted.Identity` to the AGS identity contract, the shared internal
workload identity and auth-header rules, and in-process JSON request
construction. It must not duplicate the AgentTeam identity value or import any
resource-server or runtime composition package.
`internal/agsbridge/gittransport` separately owns the process-local `meshxags`
go-git protocol and concurrent embedded-handler registry. Keeping it as a child
package prevents its process-global go-git registration from running in ordinary
`agsbridge` callers; the child package also must not import resource-server or
runtime composition packages.
`internal/agsbridge/wiki` remains separate as the AGS wiki/publication port. Generic
repository lifecycle contracts belong to `internal/service/resource/repos`; bridge
transport, lifecycle contracts, and publication behavior must not be collapsed
into one package.

## 4. Error and API translation

Domain packages own their domain error sentinels and `HTTPStatus` mapping.
Shared packages such as `internal/service/resource/repos` may expose errors for the lifecycle
contracts they own. API handlers classify errors from the exact service packages
they call; they must not import server composition only to translate an error.

## 5. Adding or moving service code

When adding resource service code:

1. Pick the domain that owns the product behavior.
2. Put cross-resource lifecycle code in `internal/service/resource/repos` only when it has no KB,
   Memory, Skill, or Automation semantics.
3. Put shared access-plane mechanics in `internal/service/resource/access` only when they do not
   import or own concrete resource service behavior.
4. Keep resource construction in the existing server composition surface; do
   not recreate a root service facade.
5. If the composition boundary itself changes, update this spec and
   `guardrails/architecture/check-meshx-service-boundaries.sh` in the same
   change with a durable reason.
