--- name: sync-upstream description: > Sync the LibreChat Mobile client with a newer official LibreChat server release. Diffs upstream tags, identifies gaps in the mobile app, proposes changes with user approval, then implements them. Use when a new LibreChat version is released. allowed-tools: Bash, Read, Glob, Grep, Write, Edit, WebFetch, WebSearch, Agent, TeamCreate, SendMessage, TaskCreate, TaskUpdate, TaskGet, TaskList argument-hint: "[target-tag] (optional, defaults to latest stable)" --- # Sync Upstream Synchronize the LibreChat Mobile app with a newer version of the official LibreChat server. This is a multi-phase, team-based workflow. You are the **team lead**. You orchestrate at a high level. You NEVER read code, write code, or grep the codebase yourself. All heavy lifting is delegated to teammates. ## Team Setup Create an Agent Team with 5 teammates at the start: | Teammate | Role | Prompt Summary | |----------|------|----------------| | **investigator** | Reads upstream diffs, analyzes API/type/UI changes, cross-references with mobile codebase | "You are the investigator for a LibreChat Mobile upstream sync. Your job is to analyze diffs between upstream tags and identify gaps in the mobile client. You have read-only responsibilities — never write code. You have WebFetch and WebSearch access so you can read GitHub release notes and changelogs in addition to local diffs." | | **android-expert** | Technical advisor on Android architecture and best practices. Cross-checks all guidance with online research before advising. | "You are the Android tech lead for a LibreChat Mobile upstream sync. You provide guidance on Android best practices, Jetpack Compose patterns, Kotlin idioms, and architectural decisions. CRITICAL: You MUST cross-check your knowledge by researching online (WebSearch/WebFetch) before giving advice. Never rely solely on training data — always verify current best practices, especially for Compose, Ktor, Koin, and Material 3. Return researched guidance to teammates who ask." | | **ios-kmp-expert** | Technical advisor on iOS and Kotlin Multiplatform architecture. Ensures KMP shared code and iOS-specific implementations follow platform conventions. | "You are the iOS/KMP tech lead for a LibreChat Mobile upstream sync. You provide guidance on Compose Multiplatform patterns, KMP expect/actual declarations, iOS platform APIs (UIKit, Foundation, Keychain, Network.framework), SKIE interop, and ensuring shared code compiles correctly for both targets. CRITICAL: You MUST cross-check your knowledge by researching online (WebSearch/WebFetch) before giving advice. Never rely solely on training data — always verify current best practices for CMP, KMP, and iOS platform conventions. Return researched guidance to teammates who ask." | | **implementer** | Writes code changes to mobile app following existing patterns and conventions | "You are the implementer for a LibreChat Mobile upstream sync. Your job is to write code changes following existing architecture patterns. Always read the module's CLAUDE.md before touching it. This project uses **Koin** for DI (NOT Hilt) — use `koinViewModel()`, `viewModelOf(::X)`, `singleOf(::X)`, and Koin modules in `feature/*/di/`. Follow safeApiCall, UDF, Ktor, @Serializable patterns. Whenever you touch a KMP module, check BOTH commonMain AND iosMain source sets — expect declarations in commonMain need actual implementations in both androidMain and iosMain. Before making significant architectural decisions, consult the android-expert or ios-kmp-expert teammate." | | **verifier** | Checks implementation correctness, runs builds, validates changes match proposal | "You are the verifier for a LibreChat Mobile upstream sync. Your job is to independently validate that implementation matches the approved proposal. Run Android build, iOS framework link, detekt, and tests. Review changes file-by-file. Flag issues. Message the implementer directly if fixes are needed — they retain context of what they changed." | **Teammate interaction pattern:** - **investigator** works independently on Phase A and B (diff + gap analysis) - **android-expert** is consulted for Android-specific architecture, Compose, and Material 3 decisions. The android-expert MUST search online to verify recommendations — do not accept advice that hasn't been cross-checked against current documentation. - **ios-kmp-expert** is consulted for KMP shared code, expect/actual patterns, iOS platform APIs, and Compose Multiplatform concerns. Same online-verification requirement as android-expert. - **implementer** does all code changes, consulting android-expert or ios-kmp-expert for non-trivial patterns - **verifier** validates after implementer finishes, messages implementer for fixes **Important:** Teammates retain context across messages. Reuse them for follow-ups — do NOT spawn new sub-agents (sub-agents lose context). Sub-agents are a last resort fallback only. ## Prerequisites Run these checks yourself (lightweight, no codebase reading). The working directory is already the mobile repo root — do **not** `cd` into a different directory. The local checkout directory name can vary (historical: `LibreChat-Android`; current upstream: `Librechat-Mobile`), so rely on relative paths from CWD rather than any hardcoded repo-dir name. ### 1. Submodule check ```bash git submodule status ``` If `upstream/` is missing: ```bash git submodule add https://github.com/danny-avila/LibreChat.git upstream git submodule update --init ``` ### 2. Version file check ```bash cat UPSTREAM_VERSION ``` If missing, create from current state: ```bash VERSION=$(grep 'SUPPORTED_BACKEND_VERSION' core/common/src/commonMain/kotlin/com/garfiec/librechat/core/common/BackendVersion.kt | grep -o '"[^"]*"' | tr -d '"') COMMIT=$(cd upstream && git rev-parse HEAD) echo "# Upstream LibreChat version this mobile build tracks." > UPSTREAM_VERSION echo "# Updated by the sync-upstream skill. Do not edit manually." >> UPSTREAM_VERSION echo "tag=v${VERSION}" >> UPSTREAM_VERSION echo "commit=${COMMIT}" >> UPSTREAM_VERSION echo "date=$(date +%Y-%m-%d)" >> UPSTREAM_VERSION ``` ### 3. Clean working tree ```bash git status --porcelain ``` If dirty, ask the user to commit or stash before proceeding. ### 4. Context recovery (new session detection) Check if a prior sync was partially done in another session: ```bash TRACKED_TAG=$(grep '^tag=' UPSTREAM_VERSION | cut -d= -f2) CODE_VERSION=$(grep 'SUPPORTED_BACKEND_VERSION' core/common/src/commonMain/kotlin/com/garfiec/librechat/core/common/BackendVersion.kt | grep -o '"[^"]*"' | tr -d '"') SUBMODULE_HEAD=$(cd upstream && git rev-parse HEAD) TRACKED_COMMIT=$(grep '^commit=' UPSTREAM_VERSION | cut -d= -f2) ``` If `TRACKED_TAG` (without `v` prefix) != `CODE_VERSION`, or `SUBMODULE_HEAD` != `TRACKED_COMMIT`: > "It looks like a sync may have been partially done. UPSTREAM_VERSION says {TRACKED_TAG} > but BackendVersion.kt says {CODE_VERSION}. Should I treat the higher version as the > current baseline, or would you like to investigate?" Wait for user response before continuing. Also check for existing artifacts from a previous partial run: ```bash ls -la .claude/sync-upstream/artifacts/ 2>/dev/null ``` If a previous proposal or phase report exists, offer to resume from that state. ### 5. Prepare artifact directory ```bash mkdir -p .claude/sync-upstream/artifacts ``` All phase outputs (diff summaries, gap reports, proposals) are persisted here so the skill is resumable if the session is compacted or dies mid-run. --- ## Phase A: Diff Analysis **Delegate to: investigator** ### A1. Assign investigation task Create a task for the investigator with this prompt: > Analyze upstream changes for a version sync. **Persist all outputs to files under > `.claude/sync-upstream/artifacts/` as you go** so the team lead can recover state if > the session is compacted. > > 1. Read `UPSTREAM_VERSION` at the repo root to get the current tracked tag and commit. > 2. Fetch latest tags: `cd upstream && git fetch --tags origin` > 3. List all tags newer than the current tracked tag: > `cd upstream && git tag --sort=-v:refname` > Filter OUT any tags containing `-rc`, `-beta`, `-alpha`. > 4. **Read GitHub release notes for every stable tag** between the current tracked tag and > the target tag (inclusive). Release notes almost always flag breaking changes that > diffs hide. For each tag: > ```bash > gh api repos/danny-avila/LibreChat/releases/tags/{tag} --jq .body > ``` > Fall back to `WebFetch` on `https://github.com/danny-avila/LibreChat/releases/tag/{tag}` > if `gh` is unavailable. Also scan commit messages: > `cd upstream && git log --oneline {current_tag}..{target_tag}` — commit subjects > from upstream maintainers are often the most candid description of what broke. > 5. Generate diffs between the current tag and {target_tag} for all paths listed in > `${CLAUDE_SKILL_DIR}/reference/upstream-paths.md`. Use `--stat` for an overview, > then request per-path file-level diffs for anything non-trivial. Paths include: > - `api/server/routes/` (including `routes/agents/`, `routes/files/`, `routes/admin/`) > - `api/server/controllers/`, `api/server/middleware/`, `api/server/services/` > - `api/models/` (Mongoose models that shape API responses) > - `packages/data-provider/src/` — especially `api-endpoints.ts`, `config.ts`, > `data-service.ts`, `parsers.ts`, `permissions.ts`, `types/`, `react-query/` > - `packages/data-schemas/src/` > - `packages/api/src/` (newer workspace introduced recently) > - `client/src/components/`, `client/src/hooks/`, `client/src/data-provider/`, > `client/src/store/`, `client/src/Providers/` > - `librechat.example.yaml`, `.env.example` (server config schema — affects `/api/config` surface) > 6. Categorize every change into exactly one of: > - **API changes**: New or modified routes, controller logic > - **Removed/deprecated endpoints**: Routes or fields that were removed or deprecated (BREAK mobile hard — cannot be deferred) > - **Type/schema changes**: New or modified data types, request/response shapes > - **New config / feature flags**: New keys in `/api/config` response that gate UI > - **UI changes**: New components, modified user flows > - **Security fixes**: CVEs, auth changes, token handling — cannot be deferred > - **Bug fixes**: Non-security fixes that may need mobile equivalents > - **Infrastructure**: Build, config, deps (usually not relevant) > 7. Write the categorized summary to > `.claude/sync-upstream/artifacts/phase-a-diff-summary.md` and report a short > version back. Include representative file paths and release-note excerpts. If `$ARGUMENTS` was provided, use it as the target tag. ### A2. Present results to user Once investigator reports back: - If no newer tags exist, tell user "Already up to date with {current_tag}" and stop. - If no `$ARGUMENTS`, present the list of available tags and ask user to pick one (default: latest stable). - Show the investigator's categorized summary. **Done when:** User has seen the diff summary and confirmed the target tag. The file `.claude/sync-upstream/artifacts/phase-a-diff-summary.md` exists. --- ## Phase B: Gap Analysis **Delegate to: investigator** (reuses context from Phase A — do NOT spawn a new agent) ### B1. Send follow-up to investigator > Now cross-reference the upstream changes you found with the mobile codebase. > Persist the gap report to `.claude/sync-upstream/artifacts/phase-b-gap-report.md`. > > 1. Read these mapping files from `${CLAUDE_SKILL_DIR}/reference/`: > - `api-mapping.md` — official routes to mobile `*Api.kt` files > - `model-mapping.md` — official TS types to Kotlin data classes > - `ui-mapping.md` — web components to mobile feature modules > 2. Read `DISCOVERY.md` at the repo root — it catalogs already-discovered backend > endpoints and their quirks. Any new endpoints must be appended there by the > implementer in Phase D. > 3. For each **API change**: > - Grep `core/network/src/commonMain/` for the corresponding endpoint (`*Api.kt` files) > - Also grep `core/data/src/commonMain/` — some repositories inline endpoint paths > - Note: exists / needs updating / missing > 4. For each **removed / deprecated endpoint**: > - Find every mobile call site and flag it as a Breaking gap > 5. For each **type / schema change**: > - Check `core/model/src/commonMain/` for the matching Kotlin data class > - Note new, removed, or type-changed fields > - **SSE-specific**: when upstream modifies streaming payloads or run events, also > check `core/model/src/.../StreamEvent.kt`, `SseContentEvent.kt`, `ToolCallRecord.kt`, > `ToolCallResult.kt`, `ToolAuthStatus.kt`. SSE shape drift is a frequent source of > silent breakage that compiles but produces wrong UI at runtime. > 6. For each **UI change**: > - Check the corresponding `feature/*/` module (commonMain + platform sources) > - Note if the feature exists, needs updating, or is missing > 7. For each **new feature flag in `/api/config`**: > - Check `core/model/src/commonMain/.../StartupConfig.kt` — new keys must be added > for the mobile app to detect the flag and gate UI accordingly > 8. **Version-gating check.** Read `core/common/src/commonMain/.../BackendVersion.kt`. > It exposes `parse()`, `isCompatible()`, and `extractVersionFromFooter()`. For any > new upstream feature that requires the target tag or higher, flag it so the > implementer adds a `BackendVersion.isCompatible(...)` check on the mobile side. > 9. **iosMain coverage check.** For every touched module under `core/*` or `feature/*`, > confirm whether `src/iosMain/kotlin/...` sources exist. If they do, the implementer > must update both commonMain AND iosMain (expect/actual pairs, platform-specific > bridges like `NWConnection` SSE transport, Keychain, etc.). Flag modules where > iosMain parity is easily missed. > 10. Categorize all gaps: > - **Breaking** (must fix): Changed or removed request/response shapes, removed/renamed > endpoints, auth changes, security fixes > - **Additive** (new feature): New endpoints, new UI features, new optional fields, > new feature flags > - **Cosmetic** (polish): UI improvements, a11y, i18n > 11. Report the categorized gap list with specific file paths for both upstream and mobile. ### B2. Receive gap report The investigator now has full context of both the upstream diff AND the mobile gaps. Keep the investigator alive for follow-up questions during Phase C. **Done when:** You have the categorized gap list, and `.claude/sync-upstream/artifacts/phase-b-gap-report.md` exists on disk. --- ## Phase C: Proposal **Lead presents to user — no delegation needed.** Take the investigator's gap report and produce a structured proposal. **Persist the proposal to `.claude/sync-upstream/artifacts/proposal-{target_tag}.md` before presenting it** so the user has a reviewable artifact and the skill can resume if the session dies. ``` ## Sync Proposal: {current_tag} → {target_tag} ### Breaking Changes ({count}) — must fix before updating version For each: what changed upstream (file reference), mobile file(s) needing updates, proposed change. ### Security Fixes ({count}) — must fix, cannot be deferred For each: CVE / patch description, mobile-side impact (if any), proposed change. ### Removed / Deprecated Endpoints ({count}) — mobile call sites must migrate For each: removed/deprecated route, mobile call sites (file paths), replacement route and migration plan. ### New Features ({count}) — recommended For each: what was added upstream, proposed mobile implementation approach, affected modules. ### New Config / Feature Flags ({count}) For each: new key in `/api/config`, proposed `StartupConfig.kt` update, whether a `BackendVersion` gate is needed. ### UI Changes Needing User Input ({count}) For each: what the web app does (file reference), why it doesn't translate directly to Compose, 2-3 concrete options. ### Deferred Items ({count}) — can wait for a future sync Items that are low priority or require significant new infrastructure. ``` ### Consult experts on non-trivial items Before presenting to the user, for any proposed change that involves: - New architectural patterns (new module, new DI scope, new navigation key) - UI patterns without an existing equivalent in the codebase - Performance-sensitive changes (list rendering, image loading, SSE throughput) - KMP shared code or expect/actual patterns - iOS-specific bridges (Network.framework, Keychain, WKWebView) Send Android-specific items to **android-expert** and KMP/iOS items to **ios-kmp-expert**: > Review these proposed mobile changes for best practices. For each item, > research online to verify the recommended approach is current (especially > for Compose, Material 3, Koin, Ktor, CMP, and iOS platform APIs). Flag any > items where modern best practices differ from what we're proposing. > {list of non-trivial items} Incorporate the experts' feedback into the proposal **and update the artifact file** before showing the user. ### Approval gate Ask the user: > Review the proposal above (also saved at `.claude/sync-upstream/artifacts/proposal-{target_tag}.md`). > Reply with: > - **approve all** — proceed with full implementation > - **approve with changes** — tell me what to modify in the proposal > - **approve partial** — list which items to implement now (rest deferred) > - **cancel** — abort, no changes made **Do NOT proceed to Phase D until the user explicitly approves.** If the user requests changes, update the proposal file AND re-present. --- ## Phase D: Implementation **Delegate to: implementer, then verifier** ### D1. Assign implementation task Create a task for the implementer with the approved change list: > Implement the following approved changes for the upstream sync from {current_tag} to {target_tag}. > > **Before touching any module:** > 1. Read the root `CLAUDE.md` for architecture rules > 2. Read `${CLAUDE_SKILL_DIR}/reference/android-architecture.md` for patterns > 3. Read the specific module's `CLAUDE.md` (e.g., `core/network/CLAUDE.md`) > 4. Read existing similar code as a pattern reference > > **Conventions (THIS PROJECT USES KOIN, NOT HILT):** > - `safeApiCall` for all network calls in repositories > - **Koin** for DI — use `viewModelOf(::X)`, `singleOf(::X)`, `factoryOf(::X)` in Koin modules at `feature/*/di/` and `core/*/di/`. Register the module in `LibreChatApplication.kt`'s `startKoin { modules(...) }` when creating a new one. > - Use `koinViewModel()` in Composables — never `hiltViewModel()` or `@HiltViewModel`. > - Unidirectional data flow: UI → ViewModel → Repository → API/Room > - `@Serializable` data classes in `core/model/` > - Ktor client patterns in `core/network/` > - For KMP modules, update BOTH `src/commonMain/` AND `src/iosMain/` (and `src/androidMain/` when relevant). `expect` declarations in commonMain REQUIRE matching `actual` implementations in every target's source set. > > **Before making non-trivial architectural decisions** (new patterns, new modules, > complex UI components), message the **android-expert** or **ios-kmp-expert** teammate. > They will research current best practices online and advise. > > **Approved changes:** > {paste the approved change list here} > > **After all code changes:** > 1. Update `SUPPORTED_BACKEND_VERSION` in `core/common/src/commonMain/kotlin/com/garfiec/librechat/core/common/BackendVersion.kt` to "{new_version}" (without `v` prefix) > 2. Advance submodule: `cd upstream && git checkout {target_tag}` > 3. Update `UPSTREAM_VERSION` at repo root: > ``` > tag={target_tag} > commit={full SHA of target_tag} > date={today's date YYYY-MM-DD} > ``` > 4. Update `DISCOVERY.md` at the repo root: append newly-discovered endpoints, removed > endpoints, and revised response shapes. Keep it accurate — future syncs depend on it. > 5. Report back the full list of files created or modified, grouped by module. ### D2. Assign verification task After implementer reports done, create a task for the verifier: > Verify the upstream sync implementation from {current_tag} to {target_tag}. > > **Build verification (run all four):** > 1. `./gradlew assembleDebug` — Android app compiles > 2. `./gradlew detekt` — static analysis passes on ALL source sets (commonMain, > androidMain, iosMain). The CI gate currently only covers commonMain, so do > not rely on CI here. If failures are found in iosMain/androidMain, report them. > 3. `./gradlew :shared:linkDebugFrameworkIosSimulatorArm64` — iOS framework links. > This catches iosMain compile errors that `assembleDebug` silently skips. > 4. `./gradlew check` — unit tests pass for touched modules > > **Correctness review:** > 5. Read the approved proposal at `.claude/sync-upstream/artifacts/proposal-{target_tag}.md`. > 6. Review every file the implementer changed: > - All approved items implemented? > - Any unapproved changes (scope creep)? > - Koin DI used (not Hilt / `@Inject`)? > - `safeApiCall` wrapping new network calls? > - For KMP modules: did the implementer touch iosMain where needed, not just commonMain? > - For new endpoints: was `DISCOVERY.md` updated? > > **Version consistency:** > 7. `SUPPORTED_BACKEND_VERSION` in `core/common/src/commonMain/.../BackendVersion.kt` matches target > 8. `UPSTREAM_VERSION` file has correct tag, commit, date > 9. Submodule is at the correct tag: `cd upstream && git describe --tags` > 10. `DISCOVERY.md` reflects endpoint additions/removals > > **If you find issues**, message the **implementer** directly to fix them. > The implementer retains context of what it changed. > > **Report back:** > - Pass/fail for each of the four build commands + any errors > - Issues found (if any) and who fixed them > - List of user-testable behaviors to verify on device — separate lists for Android and iOS where applicable ### D3. Present results to user Once verifier confirms everything passes: ``` ## Sync Complete: {current_tag} → {target_tag} ### Files Changed {grouped by module} ### What to Test {Android behaviors} {iOS behaviors} ### How to Test 1. Build: `./gradlew assembleDebug` (Android), `./gradlew :shared:linkDebugFrameworkIosSimulatorArm64` (iOS) 2. Install on device/emulator (both platforms where relevant) 3. Test each behavior listed above ### Version Updates - SUPPORTED_BACKEND_VERSION: {old} → {new} - UPSTREAM_VERSION tag: {old_tag} → {new_tag} - Submodule: pinned to {target_tag} - DISCOVERY.md: {brief summary of what was appended} ### Artifacts Proposal and phase reports saved under `.claude/sync-upstream/artifacts/`. ``` --- ## Error Recovery | Situation | Recovery | |-----------|----------| | Submodule missing | `git submodule add https://github.com/danny-avila/LibreChat.git upstream` | | `UPSTREAM_VERSION` missing | Create from `SUPPORTED_BACKEND_VERSION` + submodule HEAD | | No newer tags | Report "up to date" and stop | | Dirty working tree | Ask user to commit/stash | | Git fetch fails | Show `git remote -v`, check network | | Android build fails after changes | Verifier messages implementer to fix (both retain context) | | iOS framework link fails (but Android passes) | Implementer likely forgot iosMain updates — message them to audit iosMain source sets for affected modules | | Detekt fails (any source set) | Implementer fixes findings. Do not use `--ignore-failures`. | | User cancels at Phase C | Delete or archive the proposal artifact, tear down the team (`TeamDelete`), stop cleanly | | Version mismatch (tracked tag ≠ BackendVersion.kt) | Ask user which is the true baseline | | Session compacted mid-run | List `.claude/sync-upstream/artifacts/` — newest file indicates phase reached; resume from there | | Teammate unresponsive | Check task status, re-send message; sub-agent as last resort |