learning_ai_common_plat/docs/devops/GITEA_NPM_REGISTRY_MIGRATION.md
2026-03-23 19:02:49 -07:00

18 KiB

Gitea npm Package Registry Migration

Goal: Replace the docker-prep.sh + tarball workflow with Gitea's built-in npm package registry for @bytelyst/* shared packages.

Phase policy: use this Mac as the future single VM and validate the entire flow locally first. No Azure rollout and no publishing to any external or corporate registry in this phase.


1. Decision

We should adopt the local Gitea npm registry as the long-term package-distribution path for @bytelyst/* packages.

We should not switch directly in Azure first.

Instead, we should validate the exact end-to-end flow locally on this Mac:

  • local Gitea git hosting
  • local Gitea Actions
  • local Gitea npm package registry
  • local Docker / Docker Compose builds
  • local product repos consuming @bytelyst/* from local Gitea

Once that is stable, we replicate the same validated shape on the Azure single VM.


2. Why We Want This

Current pain

Today many repos still depend on one of these Docker-time workarounds:

  • file: references to sibling learning_ai_common_plat/packages/*
  • docker-prep.sh
  • .docker-deps or older .tarballs copy steps
  • temporary package.json rewriting before builds

This works, but it creates repeated operational drag:

  • every build may need prep
  • Dockerfiles become repo-specific and fragile
  • CI, local development, and Docker are not using one clean dependency source
  • path and build-context mismatches keep surfacing during ecosystem validation

Target outcome

We want one dependency source for shared packages:

  • local development
  • local CI via Gitea Actions
  • local Docker builds
  • later Azure single-VM builds

That dependency source should be the local Gitea npm registry.


3. Local-First Target Architecture

3.1 This Mac as the rehearsal VM

This Mac
├── local Gitea (git + actions + npm registry)
├── local Docker / Docker Compose
├── learning_ai_common_plat
└── product repos

Flow:

learning_ai_common_plat/packages/*
  ↓ build locally
  ↓ publish to local Gitea npm registry
local Gitea npm registry (localhost:3300)
  ↓ install via semver refs
product repos / Docker builds / local Gitea CI

3.2 Future Azure single VM

After the local rehearsal is proven, Azure should mirror the same shape:

Azure VM
├── Gitea
├── Gitea Actions runner
├── Gitea npm registry
├── Docker / Compose
└── same repo + build flow

The Azure plan should reuse the validated local approach, not invent a second design.


4. What Is In Scope Right Now

Included

  • validate local Gitea package-registry access
  • validate local Gitea Actions availability
  • define local-only package publish flow to local Gitea
  • define local-only consumer install flow from local Gitea
  • define local-only Docker build flow from local Gitea
  • define the later Azure single-VM replication steps

Excluded

  • Azure changes right now
  • external npm registry publishing
  • corporate registry publishing
  • non-local deployment actions
  • K3s / Helm work

5. Current Local Readiness Snapshot

Validated locally on this Mac:

  • local Gitea health endpoint responds
  • local Gitea version endpoint responds
  • local bytelyst user auth works
  • local Gitea Actions workflow exists for learning_ai_common_plat
  • local Gitea package registry endpoint is reachable
  • local pilot packages have been published to local Gitea successfully
  • a clean scratch consumer install from local Gitea works on the host

That is enough to treat this Mac as the single-VM rehearsal environment.


5.1 Validation Results So Far

Proven locally on this Mac

  • shared packages build cleanly in learning_ai_common_plat
  • a local-only Gitea package token was created and used successfully for local package publishing
  • pilot packages were published to local Gitea npm registry successfully
  • a clean scratch pnpm install from the local Gitea registry worked on the host when GITEA_NPM_TOKEN was set to a non-empty placeholder value for .npmrc env resolution
  • learning_ai_flowmonk was migrated on the host from tarball refs to semver @bytelyst/* refs
  • learning_ai_flowmonk host-side install, typecheck, and tests passed against the local Gitea registry

Important implementation finding

Publishing @bytelyst/* workspace packages with raw npm publish is not sufficient for this migration.

Why:

  • packages with internal workspace:* dependencies can be published with unresolved workspace specifiers
  • those published artifacts break downstream consumers

What worked:

  • pnpm pack produces normalized package metadata for workspace dependencies
  • publishing the normalized tarball to Gitea works

This is now codified in the local-only helper script:

scripts/publish-local-gitea-packages.sh

That script is currently the authoritative local rehearsal path for publishing @bytelyst/* packages to local Gitea.

Current blocker

The remaining blocker is not host-side package publishing or host-side package consumption.

The blocker is specifically:

  • Docker / BuildKit installs against the local Homebrew Gitea instance on this Mac
  • the Docker-side auth path, where host.docker.internal reaches the registry but placeholder-token package fetches still fail with 401 Unauthorized

At the time of writing:

  • host-side registry usage is validated
  • FlowMonk host-side pilot migration is validated
  • Docker-side local-registry validation is still blocked after auth succeeds because embedded tarball URLs still resolve to localhost:3300 inside the build container

That blocker must be resolved before we can claim full local E2E completion.


5.2 Remaining Gaps From Local Mac Validation

The local rehearsal on this Mac has proven enough to validate the host-side registry model, but it has not yet proven the full VM-ready or K8s-ready path.

Gaps still open on this Mac

  • Docker / BuildKit package installs from the local Homebrew Gitea instance are still not green
  • the Homebrew Gitea ROOT_URL / package tarball URL behavior is still fragile across host and Docker boundaries
  • Docker-side package installs currently need a real Gitea package token even though host-side installs only need non-empty GITEA_NPM_TOKEN env resolution for .npmrc
  • even with a real token, the current FlowMonk backend Docker build still fails once package metadata redirects tarball fetches to http://localhost:3300/... inside the container
  • local Gitea Actions has not yet been validated end-to-end for the package build → publish → consumer flow
  • the FlowMonk pilot is currently validated only for backend/web host-side consumption; Docker is still blocked and mobile remains outside the registry-backed pilot slice
  • not all @bytelyst/* packages have been revalidated under the local Gitea registry with a fresh consumer install after the pnpm pack publish flow changes

Why this matters for Azure

Azure should be a replication step, not a redesign step.

That means the Azure VM rollout should wait until the remaining local gaps are cleared for:

  • package metadata correctness
  • tarball URL correctness
  • Docker consumer correctness
  • local CI correctness

If we skip those validations locally, the first Azure VM trial becomes a debugging environment instead of a deployment environment.

Concrete local-exit criteria before Azure

Before starting Azure VM rollout, we should be able to demonstrate all of the following on this Mac:

  • one Gitea deployment shape whose package URLs work for both host installs and Docker builds
  • one publish path for @bytelyst/* packages that works repeatably with pnpm pack
  • one pilot repo that installs from the registry on the host and inside Docker without fallback tarballs
  • one local Gitea Actions path that can build/publish/install with the same registry assumptions
  • one documented rollback path that cleanly returns a pilot repo to tarball-based Docker consumption if needed

6. Migration Strategy

Stage A — Local registry rehearsal

Validate the package-registry path locally before changing every repo.

Required outcomes:

  1. local package token exists
  2. a small pilot set of @bytelyst/* packages can be published to local Gitea
  3. a local consumer can install them via semver refs
  4. a Docker build can install them without docker-prep.sh
  5. local Gitea Actions can run the same package build/publish path

Stage B — Pilot repo migration

Migrate one repo first.

Recommended pilot:

  • learning_ai_flowmonk

Reason:

  • recent Docker/build work already exposed its edge cases
  • both backend and web surfaces exist
  • it is a strong canary for dependency-distribution changes

Stage C — Sequential ecosystem rollout

After the pilot is stable, migrate remaining repos sequentially.


7. Local Implementation Plan

7.1 Verify package metadata in learning_ai_common_plat

Every packages/*/package.json should have:

  • a valid name
  • a valid version
  • a valid files / exports setup
  • a successful local build

Local validation command:

cd /Users/sd9235/code/mygh/learning_ai_common_plat
pnpm -r --filter './packages/*' build

7.2 Create a local-only Gitea package token

Use a token intended only for this Mac rehearsal.

Required scopes:

  • package read
  • package write

Do not use Azure or external registry credentials here.

7.3 Publish only to local Gitea

In this phase, all npm publish activity must point only to:

http://localhost:3300/api/packages/bytelyst/npm/

No Azure Artifacts. No npmjs.org. No external corporate npm registry.

Use the local-only helper script for this rehearsal:

cd /Users/sd9235/code/mygh/learning_ai_common_plat
GITEA_NPM_TOKEN='<local-token>' bash ./scripts/publish-local-gitea-packages.sh

For a single package:

cd /Users/sd9235/code/mygh/learning_ai_common_plat
GITEA_NPM_TOKEN='<local-token>' bash ./scripts/publish-local-gitea-packages.sh '@bytelyst/errors'

7.4 Start with a minimal package pilot set

Publish a small set first:

  • @bytelyst/errors
  • @bytelyst/config
  • @bytelyst/api-client

Then expand once the local install path is proven.

7.5 Consumer dependency model after migration

Consumers move from local file refs:

"@bytelyst/auth": "file:../../learning_ai_common_plat/packages/auth"

to semver refs:

"@bytelyst/auth": "^0.1.0"

And resolve via scoped .npmrc or .pnpmrc config pointing @bytelyst to local Gitea.

7.6 Docker model after migration

After a repo is migrated to the registry model, its Dockerfiles should:

  • stop copying .docker-deps or .tarballs
  • stop depending on docker-prep.sh
  • install from local Gitea through scoped registry config

That is the main operational simplification we want.


8. Local Validation Sequence

Step 1 — Validate local Gitea surfaces

Confirm locally:

  • Gitea UI is reachable
  • package registry API is reachable with auth
  • Actions workflow is visible and active

Step 2 — Validate package build output

Run local builds for the shared packages and confirm pack/publish inputs are clean.

Step 3 — Publish a minimal package pilot set to local Gitea only

Success means:

  • packages appear in local Gitea package list
  • metadata looks correct
  • no external registry interaction occurred

Step 4 — Validate local install from Gitea

Use a scratch consumer or a pilot repo surface and verify:

  • pnpm install resolves @bytelyst/* from local Gitea
  • lockfile updates are clean
  • no fallback to tarballs is required for the tested packages

Step 5 — Validate Docker build from local Gitea

For the pilot repo:

  • remove the tested surface's dependency on docker-prep.sh
  • add scoped registry config for Docker
  • build backend and web without tarball prep

Success means:

  • image build works without .docker-deps or .tarballs
  • build does not require local package rewrite logic

Current status on this Mac:

  • not yet fully green
  • the remaining issue is the local Homebrew Gitea instance serving package metadata/tarball URLs across the Docker build boundary
  • host-side validation is complete, Docker-side validation is still open

Step 6 — Validate local Gitea Actions path

Add or adapt a local-only workflow in learning_ai_common_plat that:

  • builds packages
  • optionally publishes to local Gitea npm registry
  • never targets an external registry

Step 7 — Validate full local E2E

At the end of the local rehearsal we should be able to say:

  • shared packages build locally
  • shared packages publish to local Gitea registry
  • a pilot consumer installs from local Gitea
  • a pilot Docker build succeeds from local Gitea
  • local Gitea Actions can drive the same path

Only then should we expand repo-by-repo.


Pilot

  1. learning_ai_flowmonk

Then

  1. learning_ai_local_memory_gpt
  2. learning_ai_notes
  3. learning_ai_trails
  4. learning_ai_fastgap
  5. learning_ai_clock
  6. learning_ai_jarvis_jr
  7. learning_ai_peakpulse
  8. learning_multimodal_memory_agents
  9. learning_voice_ai_agent

The ordering prioritizes recently exercised Docker paths before higher blast-radius repos.


10. CI Model For The Local Rehearsal

For the local rehearsal phase, Gitea Actions should do only local work:

  • build packages
  • test packages
  • typecheck packages
  • optionally publish to local Gitea only

This is intentionally different from a final enterprise rollout.

The objective is to prove the local VM pattern first.


11. Risks And Guardrails

Risks

  • version drift between local source and published package versions
  • peer dependency mismatches hidden by current tarball workflow
  • Docker auth/config differences from shell installs
  • accidental publishing to the wrong registry
  • switching too many repos before the pilot is stable

Guardrails

  • use local-only credentials for this phase
  • keep @bytelyst scoped registry config explicit
  • do not remove tarball fallback globally until the pilot is green
  • migrate one consumer repo at a time
  • keep rollback steps documented per repo

12. Rollback Plan

If the registry-based flow fails during pilot migration:

  1. revert the tested consumer back to its current working dependency mode
  2. restore its docker-prep.sh path if needed
  3. keep the Gitea registry work isolated to the local rehearsal branch/state
  4. fix the issue locally before retrying

No repo should lose its known-good build path until the registry model is proven.


13. Azure Single-VM Follow-Through

After the local rehearsal is green, Azure should follow the same validated recipe:

  1. provision one VM
  2. install Docker and Gitea
  3. enable Gitea Actions runner
  4. enable Gitea packages
  5. clone the same repos onto the VM
  6. apply the same local registry/token/package flow
  7. re-run the pilot repo first
  8. then expand sequentially across the ecosystem

Azure should be a replication step, not a redesign step.

What Azure still needs beyond current local proof

Even though the codebase is already designed to be highly configurable, Azure VM rollout still requires a few validations that have not been fully cleared by the local Mac rehearsal yet:

  • Gitea running in a deployment shape where package tarball URLs are stable for both host consumers and containerized consumers
  • registry-backed Docker builds for the pilot repo without docker-prep.sh
  • local Gitea Actions or equivalent host-runner proof for package build/publish/install
  • a final decision on whether mobile-facing @bytelyst/* packages stay on local file: links during the pilot phase or join the registry migration in a later wave
  • one Azure-ready secrets model for Gitea token handling, service envs, and registry auth that maps cleanly from local env vars to VM secrets/config files

What should require minimal change when moving to Azure

The good news is that most of the ecosystem has already been implemented in a way that keeps scale-up mostly configuration-driven once the registry and image flows are proven.

Expected low-change areas:

  • service code already externalizes most environment-specific values via env/config
  • Compose and K8s models already map cleanly to Deployments, Services, Ingress, ConfigMaps, and Secrets
  • Traefik, readiness probes, service ports, and namespace separation are already documented in a K8s-friendly way
  • scaling stateless services should mostly mean changing replica counts, resource requests/limits, and HPA settings
  • moving from single-node K3s to multi-node K3s or managed Kubernetes should mostly reuse the same manifests with infra-level adjustments

What is not yet proven enough to call low-change:

  • the package-distribution layer for Docker/K8s image builds
  • the exact image build/publish flow for the full ecosystem after registry migration
  • the complete repo-by-repo removal of tarball-based Docker prep

14. Definition Of Done

This migration plan is locally validated only when all are true:

  • local Gitea package publish auth verified
  • local package publish path verified for a pilot package set
  • local consumer install path verified on the host with non-empty GITEA_NPM_TOKEN env resolution
  • local Docker build path verified without docker-prep.sh
  • local Gitea Actions path verified
  • pilot repo migrated successfully end-to-end including Docker
  • rollback path documented and tested conceptually
  • Azure single-VM reproduction steps documented from the validated local process

15. Immediate Next Actions

  1. create or verify a local-only Gitea package token
  2. publish a minimal pilot @bytelyst/* package set to local Gitea only
  3. validate install from local Gitea in one pilot consumer
  4. validate Docker build from local Gitea in that pilot repo
  5. validate the same path via local Gitea Actions
  6. only then expand to broader ecosystem migration