update-dependencies

SkillDev tools

Weekly dependency update workflow for Sesori Apps Monorepo. Updates every pubspec.yaml across the bridge and client workspaces plus standalone packages, regenerates all lockfiles, re-resolves iOS/macOS SwiftPM native dependencies (Package.resolved), updates Fastlane/Gemfile versions, handles conflicts, and verifies via analyze/test/codegen.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the update-dependencies skill

What this skill tells your AI

The instructions your AI receives, as published by sesori-ai/sesori_apps_monorepo in .ai/skills/update-dependencies/SKILL.md and read by ahel’s review.

<project_structure> The repo has two Dart workspaces and two standalone packages. Workspace members share a single resolution; standalone packages resolve independently.

Client workspace (client/pubspec.yaml is the workspace root, has flutter env constraint):

  • client/pubspec.yaml — workspace root, env only
  • client/module_auth/pubspec.yaml
  • client/module_core/pubspec.yaml
  • client/module_prego/pubspec.yaml (Flutter package — theme/assets)
  • client/module_app_ui/pubspec.yaml (shared Flutter UI)
  • client/module_desktop_core/pubspec.yaml (pure Dart desktop business logic)
  • client/design_catalog/pubspec.yaml (Flutter design-system catalog)
  • client/app/pubspec.yaml (Flutter app — Firebase, flutter_bloc, etc.)
  • client/desktop/pubspec.yaml (Flutter desktop app)

Bridge workspace (bridge/pubspec.yaml is the workspace root, pure Dart):

  • bridge/pubspec.yaml — workspace root, env only
  • bridge/sesori_plugin_interface/pubspec.yaml
  • bridge/sesori_bridge_foundation/pubspec.yaml (depends on sesori_plugin_interface; bridge-wide shared primitives)
  • bridge/sesori_plugin_runtime/pubspec.yaml (depends on sesori_plugin_interface)
  • bridge/sesori_plugin_opencode/pubspec.yaml
  • bridge/sesori_plugin_codex/pubspec.yaml
  • bridge/sesori_plugin_acp/pubspec.yaml
  • bridge/sesori_plugin_cursor/pubspec.yaml
  • bridge/sesori_plugin_omp/pubspec.yaml
  • bridge/sesori_plugin_claude/pubspec.yaml
  • bridge/sesori_plugin_pi/pubspec.yaml
  • bridge/sesori_plugin_hermes/pubspec.yaml
  • bridge/sesori_plugin_copilot/pubspec.yaml
  • bridge/sesori_plugin_grok/pubspec.yaml
  • bridge/sesori_plugin_deepseek/pubspec.yaml
  • bridge/sesori_plugin_antigravity/pubspec.yaml
  • bridge/app/pubspec.yaml (CLI relay server)

Standalone packages (NOT in any workspace — resolve independently with their own lockfile):

  • shared/sesori_shared/pubspec.yaml — pure Dart; consumed by both workspaces via path: dep
  • shared/no_slop_linter/pubspec.yaml — pure Dart analyzer plugin; consumed by module_prego via path: dev_dep

IMPORTANT: Update shared/sesori_shared FIRST because both workspaces depend on it.

DO NOT update shared/no_slop_linter as part of this workflow. Its analyzer/_fe_analyzer_shared constraints span multiple majors intentionally and break easily — bumps are done manually, less often, by a human. Skip its pubspec edits in Phase 3, but still run make analyze/make test against it via the shared Makefile for verification.

<ios_files> Sesori iOS is Swift Package Manager only — there is no Podfile, and CocoaPods is not part of the iOS dependency graph. Do not run pod install or attempt to add Podfile handling here.

  • client/app/ios/Gemfile (fastlane gem only)
  • client/app/ios/Gemfile.lock </ios_files>

<android_files>

  • client/app/android/Gemfile (fastlane gem)
  • client/app/android/Gemfile.lock </android_files>

<swiftpm_files> iOS and macOS pull native dependencies (Firebase, Google SDKs, leveldb, gRPC, etc.) via Swift Package Manager. The resolved native versions are pinned in Package.resolved lockfiles. Every discovered tracked copy matters — the project copy and the workspace copy, per platform:

  • client/app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
  • client/app/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
  • client/app/ios/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved
  • client/app/macos/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved

flutter build --config-only regenerates only the project copies. The Runner.xcworkspace copies are what Xcode actually consumes when a build targets the workspace — which is exactly what the iOS release lanes do (build_app(workspace: "Runner.xcworkspace", ...) in client/app/ios/fastlane/Fastfile). Leaving them stale means the shipped TestFlight/App Store build silently links the OLD native SDKs even though the PR claims to have updated them. Verified 2026-07-21: with the workspace copy stale, xcodebuild -resolvePackageDependencies -workspace Runner.xcworkspace -scheme Runner resolved AppCheck 11.3.0 / GoogleUtilities 8.1.1 while the project copy already said 11.3.1 / 8.1.2.

Both copies describe the same package graph, so after Phase 5.1 they must end up with identical pins.

These lockfiles change on most weekly runs because native SDK patch releases land continuously, independent of pubspec.yaml. They MUST be re-resolved every run (Phase 5). Use flutter build --config-only for the project copies; a bare xcodebuild -resolvePackageDependencies honors whatever pins already exist and silently no-ops, so it only re-resolves the workspace copies once their lockfile has been deleted. Skipping (or using the wrong resolve command) is a silent, recurring miss — e.g. one past run bumped firebase-ios-sdk but left GoogleUtilities/nanopb/promises stale; another run's bare xcodebuild resolve reported "no changes" while a flutter build --config-only picked up GTMSessionFetcher 4.5.0→5.3.0, GoogleUtilities 8.1.0→8.1.1, nanopb, and Promises. </swiftpm_files> </project_structure>

List every source pubspec (excludes build artifacts, codegen output, and worktrees):

find . -name pubspec.yaml -not -path '*/build/*' -not -path '*/.dart_tool/*' -not -path './.worktrees/*' | sort

Exclude generated platform symlinks (for example ephemeral/.symlinks/plugins) from the source inventory as well.

Cross-check the output against the package inventory in <project_structure>. If a pubspec appears that is NOT listed there (a newly added workspace member), treat it as in-scope for THIS run — add it to every per-file step below (env constraints in 1.2, outdated check in 2.1, constraint bumps in 3.1) — AND update the inventory + env table in this skill so future runs inherit it. The ONLY pubspec excluded from edits is shared/no_slop_linter/pubspec.yaml.

List the authoritative workspace members straight from the workspace roots — every member here MUST be processed in Phases 1–3:

sed -n '/^workspace:/,$p' bridge/pubspec.yaml
sed -n '/^workspace:/,$p' client/pubspec.yaml

List the iOS/macOS SwiftPM lockfiles that Phase 5 will refresh (currently four tracked app copies — a project copy and a workspace copy per platform; these are native deps and are in scope). Reconcile this list with actual source Xcode projects, including client/desktop/macos: configure and resolve every discovered SwiftPM graph. A local-only graph may legitimately produce no Package.resolved; report that rather than adding an artificial lockfile.

git ls-files | grep 'Package.resolved'

Check current Flutter version and update if needed:

flutter --version
asdf install flutter latest
asdf set flutter latest   # asdf 0.16+ canonical form; equivalent to `asdf local` on older versions
flutter --version

If flutter --version still reports the old version after asdf set, run asdf reshim flutter (or open a new shell) and re-run flutter --version.

Check and update environment constraints in all pubspec.yaml files except shared/no_slop_linter/pubspec.yaml (manually managed).

Get the current Dart SDK version bundled with Flutter:

flutter --version

Note the Dart version (e.g., "Dart 3.11.0") and Flutter version (e.g., "Flutter 3.41.0").

For each pubspec.yaml below, read its environment section and update only the keys present. Preserve the existing constraint syntax per file — do not normalize between caret and range forms.

SKIP shared/no_slop_linter/pubspec.yaml entirely — its env constraint (and all other deps) are managed manually by a human.

FileHas sdkHas flutterConstraint style
client/pubspec.yamlcaret (^3.13.0) + range (">=3.47.0 <3.48.0")
client/app/pubspec.yamlcaret
client/module_auth/pubspec.yamlcaret
client/module_core/pubspec.yamlcaret
client/module_prego/pubspec.yamlcaret + range
client/module_app_ui/pubspec.yamlcaret + range
client/module_desktop_core/pubspec.yamlcaret
client/design_catalog/pubspec.yamlcaret + range
client/desktop/pubspec.yamlcaret
bridge/pubspec.yamlcaret
bridge/app/pubspec.yamlcaret
bridge/sesori_plugin_interface/pubspec.yamlcaret
bridge/sesori_bridge_foundation/pubspec.yamlcaret
bridge/sesori_plugin_runtime/pubspec.yamlcaret
bridge/sesori_plugin_opencode/pubspec.yamlcaret
bridge/sesori_plugin_codex/pubspec.yamlcaret
bridge/sesori_plugin_acp/pubspec.yamlcaret
bridge/sesori_plugin_cursor/pubspec.yamlcaret
bridge/sesori_plugin_omp/pubspec.yamlcaret
bridge/sesori_plugin_claude/pubspec.yamlcaret
bridge/sesori_plugin_pi/pubspec.yamlcaret
bridge/sesori_plugin_hermes/pubspec.yamlcaret
bridge/sesori_plugin_copilot/pubspec.yamlcaret
bridge/sesori_plugin_grok/pubspec.yamlcaret
bridge/sesori_plugin_deepseek/pubspec.yamlcaret
bridge/sesori_plugin_antigravity/pubspec.yamlcaret
shared/sesori_shared/pubspec.yamlcaret

Example:

environment:
  sdk: ^DART_VERSION
  flutter: ">=FLUTTER_VERSION <NEXT_MINOR"   # client/pubspec.yaml only

Commit if environment constraints changed:

git diff .tool-versions
git diff --name-only -- '*.yaml'
git add .tool-versions $(git diff --name-only -- '*.yaml')
git commit -m "chore: update Flutter/Dart environment constraints

- Update environment constraints in all pubspec.yaml files
- Update Flutter SDK version in .tool-versions (if changed)"

Skip this commit if no environment changes were needed.

Delete all pubspec.lock files except shared/no_slop_linter/pubspec.lock (the linter is excluded from this workflow — its lock must remain untouched so transitive resolution doesn't shift):

find . -name "pubspec.lock" \
  -not -path "./.worktrees/*" \
  -not -path "./shared/no_slop_linter/*" \
  -delete

Run outdated check for each package. Workspaces resolve as a unit (run from workspace root); standalone packages resolve individually.

Standalone (shared/sesori_shared only — no_slop_linter is excluded):

(cd shared/sesori_shared && dart pub outdated)

Client workspace (one resolution covers all members; run outdated per-member to see direct deps per package — flutter pub outdated for Flutter packages, dart pub outdated for pure-Dart members):

set -e
(cd client && flutter pub get)
(cd client/module_auth && dart pub outdated)       # pure Dart
(cd client/module_core && dart pub outdated)       # pure Dart
(cd client/module_prego && flutter pub outdated)   # Flutter (flutter: sdk: flutter)
(cd client/module_app_ui && flutter pub outdated)  # shared Flutter UI
(cd client/module_desktop_core && dart pub outdated) # pure Dart
(cd client/design_catalog && flutter pub outdated)   # Flutter design catalog
(cd client/app && flutter pub outdated)            # Flutter app
(cd client/desktop && flutter pub outdated)        # Flutter desktop app

Bridge workspace (pure Dart):

set -e
(cd bridge && dart pub get)
(cd bridge/sesori_plugin_interface && dart pub outdated)
(cd bridge/sesori_bridge_foundation && dart pub outdated)
(cd bridge/sesori_plugin_runtime && dart pub outdated)
(cd bridge/sesori_plugin_opencode && dart pub outdated)
(cd bridge/sesori_plugin_codex && dart pub outdated)
(cd bridge/sesori_plugin_acp && dart pub outdated)
(cd bridge/sesori_plugin_cursor && dart pub outdated)
(cd bridge/sesori_plugin_omp && dart pub outdated)
(cd bridge/sesori_plugin_claude && dart pub outdated)
(cd bridge/sesori_plugin_pi && dart pub outdated)
(cd bridge/sesori_plugin_hermes && dart pub outdated)
(cd bridge/sesori_plugin_copilot && dart pub outdated)
(cd bridge/sesori_plugin_grok && dart pub outdated)
(cd bridge/sesori_plugin_deepseek && dart pub outdated)
(cd bridge/sesori_plugin_antigravity && dart pub outdated)
(cd bridge/app && dart pub outdated)

Identify updates and categorize:

  • Direct updates: Can update version constraint in pubspec.yaml immediately
  • Breaking changes: Major version bumps that need code changes (separate tickets)
  • Blocked updates: Waiting on transitive dependencies

For each dependency with a major version update, check release notes:

  • Visit pub.dev/packages/{package}/changelog
  • Identify breaking changes or migration requirements
  • Note any that require code changes for later

For each pubspec.yaml, in this order:

  1. shared/sesori_shared/pubspec.yaml (consumed by both workspaces)
  2. Bridge workspace members (dependency order): bridge/sesori_plugin_interface, bridge/sesori_bridge_foundation, bridge/sesori_plugin_runtime, bridge/sesori_plugin_opencode, bridge/sesori_plugin_codex, bridge/sesori_plugin_acp, bridge/sesori_plugin_cursor, bridge/sesori_plugin_omp, bridge/sesori_plugin_claude, bridge/sesori_plugin_pi, bridge/sesori_plugin_hermes, bridge/sesori_plugin_copilot, bridge/sesori_plugin_grok, bridge/sesori_plugin_deepseek, bridge/sesori_plugin_antigravity, bridge/app
  3. Client workspace members (dependency order): client/module_auth, client/module_core, client/module_prego, client/module_app_ui, client/module_desktop_core, client/design_catalog, client/app, client/desktop

SKIP shared/no_slop_linter/pubspec.yaml — analyzer-plugin constraints are bumped manually (see the project structure note). Do not edit it here even if pub outdated reports newer versions.

Use pub outdated --show-all when comparing constraint minimums: after lockfile regeneration the default output omits already-resolved latest versions even when their declared minimums can be raised.

a) Bump version constraints for direct dependencies that have newer versions available.

For each direct dependency listed in the pub outdated output from Phase 2:

  • If the "Latest" column shows a newer version than the current constraint's minimum AND it is resolvable:
    • Update the constraint in pubspec.yaml to use the latest resolvable version as the minimum
    • Example: drift: ^2.30.1drift: ^2.31.0
  • Skip dependencies that are blocked or would require breaking changes
  • Skip dependencies using any, path:, or git: references

b) Apply the same for dev_dependencies in each file.

Run pub get for each resolution unit. Each top-level (shared/, bridge/, client/) has a Makefile with a pub-get target:

set -e
(cd shared && make pub-get)   # iterates sesori_shared + no_slop_linter (independent lockfiles)
# Verify no_slop_linter's pubspec and lockfile remain byte-for-byte unchanged.
(cd bridge && make pub-get)   # single workspace resolution
(cd client && make pub-get)   # single workspace resolution (uses dart from Flutter SDK)

After widening constraints, check pub outdated again. pub get can retain previously constrained transitive pins even when newer versions are now allowed. If that happens, run dart pub upgrade (or flutter pub upgrade) in the affected resolution root only; never upgrade shared/no_slop_linter.

If conflicts occur:

  • Identify the conflicting dependency
  • Roll back to the maximum compatible version
  • Add to conflicts tracking list
  • Re-run pub get

Verify that constraints were actually bumped — per workspace, not globally. The most common silent failure is updating one workspace (usually client) and skipping the others.

git diff --name-only -- '*.yaml' | sort

Account for EACH of the three resolution units independently:

  • sharedshared/sesori_shared/pubspec.yaml
  • bridgebridge/**/pubspec.yaml (all members, including sesori_bridge_foundation and sesori_plugin_runtime)
  • clientclient/**/pubspec.yaml

For each, confirm one of two outcomes: either (a) its pubspec(s) appear in the diff because you bumped constraints, OR (b) you can point to the Phase 2 outdated output showing it genuinely had no upgradable direct/dev deps.

HALT if any workspace is neither changed nor provably already-current. A workspace that had outdated packages but shows no diff means you skipped it — revisit step 3.1 for that specific workspace. Do not continue until all three are accounted for.

Run analysis on every package via the Makefile targets — do not call dart analyze / flutter analyze per package by hand. Each top-level Makefile iterates its members in dependency order:

set -e
(cd shared && make analyze)   # sesori_shared + no_slop_linter
(cd bridge && make analyze)   # all bridge members, in workspace dependency order
(cd client && make analyze)   # all client members, in workspace dependency order (with --fatal-infos)

Run tests for every package via the Makefile targets. Each test target skips members without a test/ dir and uses flutter test for the Flutter app:

set -e
(cd shared && make test)
(cd bridge && make test)
(cd client && make test)

If build or tests fail:

  • Identify the failing dependency
  • Check if code changes are needed
  • Either fix the issue or roll back the dependency
  • Re-run until successful

Run code generation via the Makefile targets. Each Makefile only iterates members that have active generators (skipping no_slop_linter):

set -e
(cd shared && make codegen)   # sesori_shared
(cd bridge && make codegen)   # all bridge members with build_runner dependencies
(cd client && make codegen)   # all client members with active generators

If a generator dependency is later added to a currently-skipped package, update CODEGEN_MODULES in the matching Makefile rather than re-introducing per-package commands here.

Re-resolve SwiftPM native dependencies (Package.resolved) for iOS and macOS.

These lockfiles pin the native Firebase / Google / gRPC / leveldb versions pulled in transitively by the Flutter native plugins. They drift independently of pubspec.yaml (new native patch releases land continuously), so they MUST be re-resolved every run — skipping this leaves native deps stale even when Dart deps are current.

Use flutter build --config-only, NOT xcodebuild -resolvePackageDependencies. flutter build --config-only runs the full iOS/macOS build configuration: it regenerates the FlutterGeneratedPluginSwiftPackage from the (already-bumped, post-Phase-3) plugin versions AND re-resolves SwiftPM at the project level, writing the newest versions allowed by those constraints into the build-authoritative Runner.xcodeproj/project.xcworkspace/.../Package.resolved. A bare xcodebuild -resolvePackageDependencies honors the existing pins and silently no-ops — it will NOT pick up new native patch releases (this was a real recurring miss). --config-only stops after configuration (no compile); --no-codesign avoids signing on the iOS release config.

set -e
if command -v xcodebuild >/dev/null 2>&1; then
  (cd client/app && flutter build ios --config-only --release --no-codesign)
  (cd client/app && flutter build macos --config-only --release)
  (cd client/desktop && flutter build macos --config-only --release)
else
  echo "xcodebuild unavailable (non-macOS host) — record SwiftPM resolution as deferred in the conflict list"
fi

This updates the two Runner.xcodeproj/project.xcworkspace/.../Package.resolved files (see <swiftpm_files>). Notes:

  • Run flutter build from the owning shell (client/app for iOS/macOS; client/desktop for its macOS graph), not the client workspace root. Apply the workspace resolve and project fallback below to each discovered shell/platform pair. flutter build runs flutter pub get and regenerates the SwiftPM package itself, so there is no separate pub-get step and no stale-generated-package window to guard against.
  • These commands are macOS + Xcode only, and under set -e they would abort the whole run on a non-macOS host; the command -v xcodebuild guard lets the workflow continue and record SwiftPM as deferred instead of silently skipping.

Then refresh the workspace copies, which flutter build does not maintain but the release lanes build against. xcodebuild -resolvePackageDependencies honors whatever pins already exist, so the file must be DELETED first to force a fresh resolve. Point -clonedSourcePackagesDirPath at a scratch dir: the shared SwiftPM clone cache can hold stale tag data and silently re-resolve the OLD versions even on a deleted lockfile.

set -e
if command -v xcodebuild >/dev/null 2>&1; then
  for native_dir in client/app/ios client/app/macos client/desktop/macos; do
    lockfile="$native_dir/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved"
    backup="$(mktemp)"
    if [ -f "$lockfile" ]; then cp "$lockfile" "$backup"; fi
    rm -f "$lockfile"
    if (cd "$native_dir" && xcodebuild -resolvePackageDependencies \
      -workspace Runner.xcworkspace -scheme Runner \
      -clonedSourcePackagesDirPath "$(mktemp -d)"); then
      rm "$backup"
    else
      if [ -s "$backup" ]; then mv "$backup" "$lockfile"; else rm "$backup"; fi
      exit 1
    fi
  done
fi

Shortened here. Read the whole file on GitHub.

Signals

GitHub stars
119
Forks
8
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
update-dependencies-sesori-ai
Source
github.com/sesori-ai/sesori_apps_monorepo