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.
| Concern | Owner | Write authority |
|---|---|---|
| Canonical Spine entities, relationships, lineage, promotion records, audit | Platform | Pipeline promotion, sole writer |
| Operational Spine — connections, connectors, sync jobs, webhooks, schemas, capabilities, timeline | Platform | The service owning the runtime object |
| Organisational memory | Platform | Promotion gate — governance lives with the gate |
| Model providers, models, capability registry, agent runtime | Platform | Platform |
| Operational store, active context, projection cache | Product | Writes freely — this is its state |
| Personal · agent · conversational memory | Product | Writes freely; proposes to organisational memory |
| Agent contracts and invocation, host adapters, Workbench UI | Product | Product |
| Projections | Product | Derived — 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.
| Concern | Repo | Reason |
|---|---|---|
| Agent runtime (reasoning, tool invocation, model routing) | Platform | Needs Spine access and sits behind the governance gate |
| Agent contracts (Twin · Triage · Governance · Entity Resolver · Evidence) | Product | Consumed as types; defined once |
| Agent working memory and session state | Product | Operational, high-churn, session-scoped |
| Model providers and model selection | Platform | Policy 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:
- Before the split — make
apps/webconsume the SDK for at least one real path
(/api/v1/workspace/discoveryis 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. - During the split — publish
@integratewise/sdkand@integratewise/spine-schemaat
0.x, explicitly unstable, with a note that the contract is not frozen until S0 closes. - After S0 closes — freeze to
1.0. Not before. A1.0around 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.
| # | Step | Why here |
|---|---|---|
| 0 | Land the S0 hard-fail in the split commit. Replace the console.warn swallow so a failed or skipped canonical write cannot return success: true | Non-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 |
| 1 | Freeze the shared contract surface: spine-schema, types, contracts/shared-workbench. Version at 0.x unstable | These become a cross-repo API the moment the split lands |
| 2 | Make apps/web consume the SDK on one real path | Proves the seam before it becomes a boundary (§3) |
| 3 | Add "private": true to the 16 unmarked packages | Cheaper now than after; prevents accidental publish from either repo |
| 4 | Create integratewise-product; move apps/web, UI packages, adapters. Preserve git history (git subtree split or filter-repo) | The move itself |
| 5 | Wire Product → Platform via workspace link, then published 0.x | |
| 6 | Repair S0 fully — route canonical writes through SPINE to Neon; delete CANONICAL_SPINE_DB | In Platform, where it lives |
| 7 | Resolve S8 — one surviving Spine writer; retire pipeline/src/spine/ | |
| 8 | Wire Hermes; add spine to CORE_SERVICES | |
| 9 | Repair the 15 dangling bindings and 5 test/prod leaks in both repos; extend validate-platform-deployment.sh | Now a two-repo invariant |
| 10 | Consolidate 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 |
| 11 | Prove one connector lifecycle and one governed action end to end | Architecture Appendix K, 13–14 |
| 12 | Freeze contracts to 1.0 | Only 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
- Exactly one canonical writer, in Platform. Product proposes; Platform commits
- Synchronisation operational → canonical is one-way, through the promotion gate
- No adapter redefines canonical entities, governance policy or projection semantics
- The same
packages/domainserves web, MCP and plugin apps - Profile is resolved server-side and never becomes a build variant
- Only
@integratewise/sdkand@integratewise/spine-schemaare publishable, from Platform - No
env.testtarget equals anyenv.prodtarget, in either repository, for any binding class - A canonical write that fails or is skipped never returns success
- Neither repository contains a second credential store, provider-execution path or canonical database
7. Open questions
| # | Question | Blocks |
|---|---|---|
| R1 | Does apps/marketing stay in Platform, or move to its own deployment? | Low-risk either way; default is stay |
| R2 | Workspace link or published 0.x during steps 4–11? | Link is faster; published is closer to the end state |
| R3 | Do apps/mobile and apps/desktop (10 files combined) move, or archive? | Architecture Tier 5 already asks for a verdict |
| R4 | Who 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