Skip to Content
Design DecisionsFork with Upstream

Fork-with-upstream solution provisioning; the LLM is the glue

Status: Accepted · Date: 2026-06 (month as recorded; private-repo forking enabled on both orgs as of 2026-06-01) · Area: Solutions

Context

Creating a new Trajectory solution means standing up its two repos under the three-repo split (ADR-006): a customer repo from solution-template (into the maxq-labs-orbit-solutions org) and an internal repo from solution-template-internal (staying in maxq-labs-orbit-platform). The templates and the vendored methodology keep evolving, so a mechanism was needed that lets existing solutions pull future template updates. There was also a process question: how much of this should an LLM skill do itself versus delegate.

Decision

  • A true GitHub fork with rename (gh repo fork --org --fork-name), not a template-generate and not clone-and-push. Chosen specifically to keep the “forked from” upstream link, so each solution can pull future template/methodology updates via GitHub Sync fork / gh repo sync. The script must never sever this link (no re-init or squash). Both repos are private; private-repo forking is enabled on both orgs.
  • One naming rule: inputs are an organization name and a solution name — each letters-and-hyphens only, at most 20 characters, no leading/trailing hyphen, lowercased. Repo base solution-<org>-<sol>; the internal repo adds -internal; solution.yaml identity is seeded from the same slugs.
  • The LLM is the glue; the deterministic work is the script. The capability ships as a script + thin skill pair (.claude/skills/create-solution/ with fork-solution-repos.sh); the skill never runs gh/git itself.
  • Validation before mutation: naming rules and GitHub uniqueness are checked before any fork is created (the --dry-run path, which doubles as a leftover-partial-fork check). Schema validation of the seeded solution.yaml is best-effort only, not a gate.
  • Deliberately minimal v1 scope: fork both repos and initialize the customer solution.yaml — no README edits, no internal-repo seeding, no local clone or .env wiring.

Consequences

  • Every solution stays connected to its templates; template fixes flow forward with git-native tooling instead of manual copying.
  • The same naming rule now also governs registry identifiers — the customer id is the org slug of solution naming (ADR-008) — so one validateName covers customers, tenants, and solutions.
  • The mechanism was later ported wholesale to the in-product native-octokit path (ADR-012), where the cross-org fork of a private source turned out to require a classic PAT.
  • Recorded operational gotchas: with two gh accounts logged in, the active token silently being the wrong one surfaces as HTTP 404 (not 403) on the forks endpoint; and the working token lacks delete_repo, so cleanup of a test run is a manual GitHub-UI delete.

Evidence

  • .claude/skills/create-solution/SKILL.md + fork-solution-repos.sh
  • implementation/aurora-webapp/codebase/src/lib/solutions/naming.ts — the ported naming rule
  • memory/create-solution.md (mechanism decisions and gotchas), memory/orbit-platform-landscape.md (how the repos fit the platform)