Unclassified

Repository Topology and Migration

Status: Proposed
Document type: Specification (records decision D8)
Authority: Subordinate to INTEGRATEWISE_ARCHITECTURE.md
Canonical sections implemented: §8 (Truth) · §15.5 (Create once, deploy anywhere) · §16.7 (Product/Platform ownership) · §17 (Environments)
Owner: Founder + Platform
Version: 1.0
Last verified against: HEAD d941a422
Last verified date: 2026-07-31
Supersedes: the three-repo proposal of 2026-07-31


1. Decision

Two repositories, split by write authority — not by distribution channel.

Platform owns canonical truth and everything authorised to write it.
Product owns operational state, agent working memory, and every surface — as adapters
over one domain.

Three profiles — development, customer_zero, external — apply to both repositories
as runtime data, never as branches, directories or build variants (§4).

1.1 Why not split by channel

The earlier proposal placed the Plugin Marketplace and MCP Marketplace in separate
repositories. They are not two products; they are two adapters over one domain
(architecture §15.5: domain logic is built once; hosts are adapters).

A repository boundary between them makes them peers, and peers drift. The onboarding state
machine is the concrete case: consent_required → binding → hydrating → active must be
byte-identical across channels, and a git boundary between the channels converts that
requirement from a compiler guarantee into a discipline. It also makes every future host —
Slack, Microsoft, embedded — a new repository rather than a new folder.

Splitting by write authority gets the separation the proposal wanted (platform vs surface)
without institutionalising the channel fork.

1.2 What each repository may write

This table is the boundary. Everything else follows from it.

ConcernOwnerWrite authority
Canonical Spine entities, relationships, lineage, promotion records, auditPlatformPipeline promotion, sole writer
Operational Spine — connections, connectors, sync jobs, webhooks, schemas, capabilities, timelinePlatformThe service owning the runtime object
Organisational memoryPlatformPromotion gate — governance lives with the gate
Model providers, models, capability registry, agent runtimePlatformPlatform
Operational store, active context, projection cacheProductWrites freely — this is its state
Personal · agent · conversational memoryProductWrites freely; proposes to organisational memory
Agent contracts and invocation, host adapters, Workbench UIProductProduct
ProjectionsProductDerived — never a write target

Synchronisation is one-way with a gate. Operational state promotes to canonical through
the existing path (Continuity Bridge → Promotion). There is no bidirectional merge, and
there is no second canonical writer. If the Product repo needs something to be true, it
proposes; the Platform repo commits.

Organisational memory stays with Platform because it is governed. Memory that requires
the promotion gate lives where the gate lives. Personal, agent and conversational memory are
evidence (§8.2c) and belong with the surfaces that generate them.


2. Repository contents

2.1 integratewise-platform

services/          gateway · pipeline · spine · connector · connector-sync
                   mcp-connector · knowledge · continuity · intelligence
                   workflow · hermes · mcp-pool · marketplace-installation
packages/          spine-entities · spine-schema · types · connector-contracts
                   connectors · lib · rbac · tenancy · projection-engine · sdk
migrations/        canonical schema — one root, one sequence
infrastructure/    connector catalog · models · MCP tools registry · ADK
apps/              marketing                  ← no truth authority, no runtime coupling
docs/              architecture · specifications · adr · runbooks · evidence · changelog

Publishes @integratewise/sdk and @integratewise/spine-schema. Nothing else is publishable
(architecture S12 — 16 packages currently omit private; fix during the split, not after).

apps/marketing stays here because it carries no truth authority and no
runtime coupling. Moving it buys nothing and costs a deployment path.

2.2 integratewise-product

packages/
  domain/                application services; consumes canonical contracts, defines none
  projections/           projection consumers
  adk/                   agent contracts — not runtime
  workbench-ui/          composition
  ui-kit/                primitives
  host-contracts/        adapter interface
adapters/
  web/  mcp/  plugin/    ← the three channels. Adapters, not repositories.
  slack/  microsoft/  embedded/     ← future: folders, not repositories
apps/
  web/                   browser Workbench
  mcp-server/            IW-Spine-Network MCP
  plugin-app/            IW-Spine-Network Plugin
  preview/

Consumes @integratewise/sdk and @integratewise/spine-schema. One operational store.
One agent-memory implementation. Three adapters over them.

No adapter may redefine canonical entities, governance policy or projection semantics.
The falsifiable test: the same packages/domain serves all three apps, and an adapter
contains no policy and no canonical schema.

2.3 Agents — resolving the ambiguity

The original proposal placed agents in both the monorepo and each frontend. That cannot hold:
two Twin implementations is a Twin Law violation.

ConcernRepoReason
Agent runtime (reasoning, tool invocation, model routing)PlatformNeeds Spine access and sits behind the governance gate
Agent contracts (Twin · Triage · Governance · Entity Resolver · Evidence)ProductConsumed as types; defined once
Agent working memory and session stateProductOperational, high-churn, session-scoped
Model providers and model selectionPlatformPolicy decision, not a surface decision

In plugin_host the platform ships no inference at all — the host's model reasons, and
IntegrateWise supplies tools, truth, memory, governance and UI. The agent runtime in Platform
serves the web and mcp_workbench channels.


3. The SDK is not a boundary yet

Verified at HEAD: @integratewise/sdk has zero dependencies and six consumers, all
inside services/gateway
. Nothing in apps/web imports it.

Making an unexercised interface the contract between two repositories is how contracts get
frozen wrong. Therefore:

  1. Before the split — make apps/web consume the SDK for at least one real path
    (/api/v1/workspace/discovery is the obvious candidate; it is already the first canonical
    read). If the SDK cannot serve that path, the split has found a gap and the gap is the
    work.
  2. During the split — publish @integratewise/sdk and @integratewise/spine-schema at
    0.x, explicitly unstable, with a note that the contract is not frozen until S0 closes.
  3. After S0 closes — freeze to 1.0. Not before. A 1.0 around a canonical store that
    does not persist is a promise about behaviour nobody has observed.

Consume via workspace link or a local registry during the transition; publish to npm only
once the registry authorisation gate (architecture step 2) has passed.


4. Profiles are runtime data, not repository structure

development · customer_zero · external apply within both repositories. They are
not branches, directories, build variants or separate deployments of the same code.

Profile   ×   Surface   =   deployment configuration
                            (not a codebase, not a build)

per repo:  one build per surface (dev · test · prod)
           profile resolved server-side at the Gateway
           returned in the capability manifest

Only five modules vary by profile — MCP Pool administration, Capability Manager,
Administration, Billing, Deployments (architecture §15.1). Everything else varies by tenant
scope
, which RBAC already handles.

If profile becomes a build variant you get nine artifacts to keep in sync and eighteen new
drift sites
— precisely the outcome §15.1 exists to prevent. The frontend never computes
the profile table and never receives the definitions of modules its profile excludes.

Environment isolation is unchanged and now spans two repos: no env.test target may equal
any env.prod target, for any binding class, in either repository.


5. Migration sequence

Decision of 2026-07-31: split now, repair inside the new structure. That is workable, but
the ordering below is not negotiable — step 0 exists because the window between split and
repair is the dangerous part.

#StepWhy here
0Land the S0 hard-fail in the split commit. Replace the console.warn swallow so a failed or skipped canonical write cannot return success: trueNon-negotiable. During the transition the Product repo builds against canonical persistence it cannot see. Today that path reports success and writes nothing. Split without this and the new repo receives silent lies instead of errors — with the Platform code no longer in view
1Freeze the shared contract surface: spine-schema, types, contracts/shared-workbench. Version at 0.x unstableThese become a cross-repo API the moment the split lands
2Make apps/web consume the SDK on one real pathProves the seam before it becomes a boundary (§3)
3Add "private": true to the 16 unmarked packagesCheaper now than after; prevents accidental publish from either repo
4Create integratewise-product; move apps/web, UI packages, adapters. Preserve git history (git subtree split or filter-repo)The move itself
5Wire Product → Platform via workspace link, then published 0.x
6Repair S0 fully — route canonical writes through SPINE to Neon; delete CANONICAL_SPINE_DBIn Platform, where it lives
7Resolve S8 — one surviving Spine writer; retire pipeline/src/spine/
8Wire Hermes; add spine to CORE_SERVICES
9Repair the 15 dangling bindings and 5 test/prod leaks in both repos; extend validate-platform-deployment.shNow a two-repo invariant
10Consolidate the three memory scopes into one Product implementation; add agent_memory to D1 before retiring pipeline/src/spine/Sole definition of agent_memory is inside the file being deleted
11Prove one connector lifecycle and one governed action end to endArchitecture Appendix K, 13–14
12Freeze contracts to 1.0Only now is there observed behaviour to promise

5.1 Risk this sequence accepts

Splitting before repair means that between steps 4 and 6, the Product repo is built against a
canonical store that does not persist. Step 0 converts that from silent to loud, which is the
whole mitigation. It does not eliminate the risk — it makes it visible on the first failing
write instead of the first missing record months later.

The second accepted risk: cross-repo changes during steps 6–10 require coordinated commits.
For a team of one to three, that cost is real. It is the price of the chosen sequencing and
should be spent deliberately, not discovered.


6. Invariants

  1. Exactly one canonical writer, in Platform. Product proposes; Platform commits
  2. Synchronisation operational → canonical is one-way, through the promotion gate
  3. No adapter redefines canonical entities, governance policy or projection semantics
  4. The same packages/domain serves web, MCP and plugin apps
  5. Profile is resolved server-side and never becomes a build variant
  6. Only @integratewise/sdk and @integratewise/spine-schema are publishable, from Platform
  7. No env.test target equals any env.prod target, in either repository, for any binding class
  8. A canonical write that fails or is skipped never returns success
  9. Neither repository contains a second credential store, provider-execution path or canonical database

7. Open questions

#QuestionBlocks
R1Does apps/marketing stay in Platform, or move to its own deployment?Low-risk either way; default is stay
R2Workspace link or published 0.x during steps 4–11?Link is faster; published is closer to the end state
R3Do apps/mobile and apps/desktop (10 files combined) move, or archive?Architecture Tier 5 already asks for a verdict
R4Who owns contracts/shared-workbench after the split?Currently the only versioned cross-surface contract outside packages/

Related: Architecture §8, §15.5, §16.7 ·
Host-Aware Continuity Runtime Spec §19 ·
Marketplace Channels and Data Flow Spec