Skip to main content

Context

All Eigenoid code currently lives in a single personal repository (andylow92/SPIRE-A2A-Protocol). This repo contains two components with different lifecycles, tech stacks, and audiences:

  • Core: Python package (eigenoid/), Dockerfile.agent, tests, examples. Consumers: developers integrating agents, CI/CD pipelines, the Docker runtime.
  • Studio: React/Vite app + FastAPI backend (studio/). Consumers: agent topology designers, operators deploying from the UI.

With the creation of the eigenoid organization (ADR-0001), this is the natural moment to separate these components into independent repos. Keeping them together has the following problems:

  • Coupled versioning: a CSS change in Studio generates a release that includes non-existent changes in Core.
  • Unnecessarily broad CI: a frontend PR triggers Python tests and vice versa.
  • Unclear ownership: CODEOWNERS cannot be cleanly assigned to each component separately.
  • Implicit dependency: Studio appears to depend on Core because they share the same tree, but the dependency is actually operational (Dockerfile.agent + eigenoid as a pip package inside Docker containers), not a direct import in the backend process.

Decision

We split the monorepo andylow92/SPIRE-A2A-Protocol into two repositories within the eigenoid organization:

  • eigenoid/core: Python package, Dockerfile.agent, config, docs, tests, examples.
  • eigenoid/studio: React/Vite frontend, FastAPI backend, startup scripts.

Decoupling the Studio backend

The Studio backend (server.py) had a _find_eigenoid_root() function that walked the directory tree upward looking for Dockerfile.agent. This coupling is resolved with:

  1. EIGENOID_CORE_ROOT environment variable: the backend checks this first to locate the Core project (Dockerfile.agent and deploy workspace).
  2. Fallback walk-up: if the variable is not set, the legacy behavior of searching upward for Dockerfile.agent is preserved (useful when both repos are co-located).
  3. start.sh auto-detects sibling: if ../core/Dockerfile.agent exists, EIGENOID_CORE_ROOT is exported automatically.

Studio → Core dependency

Studio does not import eigenoid directly in its Python process. The only references to eigenoid are:

  • Code generation (TypeScript → Python strings): codegen.ts generates from eigenoid import ... as text.
  • Scripts injected into Docker containers: the backend builds Python scripts that run inside containers where eigenoid is already installed as a pip package via Dockerfile.agent.

Therefore, the dependency is: Studio needs a local copy of eigenoid/core only for deploy (Docker build context). For pure design (canvas + YAML + code preview), Studio is fully self-contained.

Consequences

  • Independent versioning: Core and Studio can have their own releases and changelogs.
  • Focused CI: each repo runs only its own tests and linters.
  • Clear CODEOWNERS: different teams can be assigned to each repo.
  • Independent deployment: Studio can be deployed as a static SPA without Core; the deploy backend requires EIGENOID_CORE_ROOT.
  • Slightly more complex dev setup: developers who want end-to-end deploy must clone both repos (or use EIGENOID_CORE_ROOT). Mitigated by auto-detection in start.sh.
  • Original monorepo becomes an archive: andylow92/SPIRE-A2A-Protocol can be archived once the last artifacts are migrated.

Alternatives considered

  • Keep monorepo in the org (eigenoid/eigenoid): zero migration effort, but inherits all the coupling problems described. Does not scale when more components are added (CLI, dashboard, docs site).
  • Monorepo with workspaces (Turborepo / Nx): solves selective CI but adds extra tooling, does not resolve ownership, and the repo remains a single blob.
  • Subtree split (git subtree): preserves history but creates complexity in PR and merge workflows. The monorepo history is preserved in the original repo; we do not need to replicate it.

References