update

SkillDev tools

Update local Egregore environment — sync the framework from upstream, run post-update migrations, and pull repos. Use for /update or when framework behavior seems broken or missing.

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 skill

What this skill tells your AI

The instructions your AI receives, as published by egregore-labs/egregore in .codex/skills/update/SKILL.md and read by ahel’s review.

Update local Egregore environment — sync framework from upstream and pull repos.

When to invoke

User says: "/update", "update Egregore", "sync the framework", "get the latest framework" — or framework behavior seems broken or missing (the first thing to try). Not this: syncing managed repos + memory only, no framework sync → /pull

What to do

  1. Sync framework from upstream (egregore-labs/egregore)
  2. Run post-update migrations (bin/post-update.sh)
  3. Run /pull (sync base branch + memory)
  4. Show what changed

Step 1: Detect environment

Detect the base branch and whether we're in a worktree. Framework updates MUST land on the base branch, never on working branches.

# Detect base branch: develop if it exists, otherwise main
BASE_BRANCH="main"
git show-ref --verify --quiet refs/heads/develop 2>/dev/null && BASE_BRANCH="develop"

CURRENT_BRANCH=$(git branch --show-current)

# Detect worktree: .git is a file (not a directory) in worktrees
IN_WORKTREE="false"
if [ -f .git ]; then
  IN_WORKTREE="true"
  WT_GITDIR=$(sed 's/^gitdir: //' .git)
  MAIN_DIR=$(cd "$WT_GITDIR/../../.." && pwd)
fi

Step 2: Sync framework to base branch

Egregore is a framework — updates come from upstream, not from your own repo's history.

Freeze lever — check FIRST, before touching any remote:

UPSTREAM_URL=$(jq -r '.upstream_url // empty' egregore.json 2>/dev/null)

If UPSTREAM_URL is "none", this instance does not pull framework from upstream — it is either the framework source of truth (framework changes are authored here and flow OUT via /sync-public) or deliberately frozen. Skip Step 2 entirely — do NOT add an upstream remote, do NOT checkout any path. Tell the user: ⛔ upstream_url is "none" — this instance never pulls framework from upstream. Skipping framework sync; running migrations + /pull only. Then continue with Step 3. A wholesale upstream checkout on a source-of-truth instance reverts downstream work (the 578deee incident: 23 files, −1131 lines).

In a worktree: The base branch is checked out in the main repo. Use git -C to update it there — git checkout $BASE_BRANCH would fail since git won't let two worktrees share a branch.

Not in a worktree: Switch to the base branch directly.

# Ensure upstream remote exists (honor a custom upstream_url when set)
UPSTREAM="${UPSTREAM_URL:-https://github.com/egregore-labs/egregore.git}"
if [ "$IN_WORKTREE" = "true" ]; then
  git -C "$MAIN_DIR" remote add upstream "$UPSTREAM" 2>/dev/null \
    || git -C "$MAIN_DIR" remote set-url upstream "$UPSTREAM"
  git -C "$MAIN_DIR" fetch upstream main --quiet
else
  git remote add upstream "$UPSTREAM" 2>/dev/null \
    || git remote set-url upstream "$UPSTREAM"
  git fetch upstream main --quiet
fi

Worktree path

if [ "$IN_WORKTREE" = "true" ]; then
  # Sync framework in main repo (on base branch)
  for p in bin/ .claude/commands/ .claude/skills/ .claude/hooks/ .claude/context/ .claude/agents/ .pi/ loom/ CLAUDE.md skills/; do
    git -C "$MAIN_DIR" checkout upstream/main -- "$p" 2>/dev/null || true
  done

  # Regenerate AGENTS.md. It is GENERATED from CLAUDE.md by
  # bin/codex-render-spec.mjs and is deliberately NOT in the path loop above —
  # so without this step downstream workspaces never receive AGENTS.md framework
  # changes (e.g. the Claude-Code runtime-precedence guard). Regenerate from the
  # freshly-synced CLAUDE.md + script; fall back to the prebuilt upstream copy if
  # node is unavailable or the render fails.
  if command -v node >/dev/null 2>&1 && [ -f "$MAIN_DIR/bin/codex-render-spec.mjs" ]; then
    node "$MAIN_DIR/bin/codex-render-spec.mjs" 2>/dev/null \
      || git -C "$MAIN_DIR" checkout upstream/main -- AGENTS.md .codex/spec-manifest.json 2>/dev/null || true
    [ -f "$MAIN_DIR/bin/pi-render-spec.mjs" ] && node "$MAIN_DIR/bin/pi-render-spec.mjs" 2>/dev/null || true
  else
    git -C "$MAIN_DIR" checkout upstream/main -- AGENTS.md .codex/spec-manifest.json 2>/dev/null || true
  fi

  # Regenerate Codex adapter skills from the freshly-synced Claude skills.
  # Generated adapters carry a marker; hand-written natives are never touched.
  # Without this, adapters for changed skills go stale until the next manual run.
  [ -f "$MAIN_DIR/bin/codex-sync-skills.sh" ] && (cd "$MAIN_DIR" && bash bin/codex-sync-skills.sh) >/dev/null 2>&1 || true

  # Restore org-owned skills (egregore.json → owned_skills[]) before committing.
  # On a name collision the org's committed version wins; the script reports it.
  (cd "$MAIN_DIR" && bash bin/restore-owned-skills.sh) || true

  # Show what changed
  git -C "$MAIN_DIR" diff --stat HEAD

  # Commit on base branch in main repo (.codex/skills/ carries the
  # regenerated adapters)
  git -C "$MAIN_DIR" add -A .claude/ .pi/ bin/ loom/ CLAUDE.md skills/ AGENTS.md .codex/spec-manifest.json .codex/skills/ 2>/dev/null
  if ! git -C "$MAIN_DIR" diff --cached --quiet 2>/dev/null; then
    EGREGORE_FRAMEWORK_UPDATE=1 git -C "$MAIN_DIR" commit -m "Update Egregore framework from upstream"
    git -C "$MAIN_DIR" push origin "$BASE_BRANCH" --quiet 2>/dev/null || true
  fi

  # Rebase worktree branch onto updated base
  git stash --quiet 2>/dev/null || true
  git fetch origin "$BASE_BRANCH" --quiet
  if ! git rebase "origin/$BASE_BRANCH" --quiet 2>/dev/null; then
    git rebase --abort 2>/dev/null || true
    echo "⚠ Rebase had conflicts — aborted. Run: git rebase origin/$BASE_BRANCH and resolve manually."
  fi
  git stash pop --quiet 2>/dev/null || true
fi

Non-worktree path

if [ "$IN_WORKTREE" = "false" ]; then
  SWITCHED="false"

  if [ "$CURRENT_BRANCH" != "$BASE_BRANCH" ]; then
    git stash --quiet 2>/dev/null || true
    git checkout "$BASE_BRANCH" --quiet 2>/dev/null
    SWITCHED="true"
  fi

  # Sync ALL framework paths
  for p in bin/ .claude/commands/ .claude/skills/ .claude/hooks/ .claude/context/ .claude/agents/ .pi/ loom/ CLAUDE.md skills/; do
    git checkout upstream/main -- "$p" 2>/dev/null || true
  done

  # Regenerate AGENTS.md from the freshly-synced CLAUDE.md (it is generated by
  # bin/codex-render-spec.mjs and not in the path loop above). Fall back to the
  # prebuilt upstream copy if node is unavailable or the render fails.
  if command -v node >/dev/null 2>&1 && [ -f bin/codex-render-spec.mjs ]; then
    node bin/codex-render-spec.mjs 2>/dev/null \
      || git checkout upstream/main -- AGENTS.md .codex/spec-manifest.json 2>/dev/null || true
    [ -f bin/pi-render-spec.mjs ] && node bin/pi-render-spec.mjs 2>/dev/null || true
  else
    git checkout upstream/main -- AGENTS.md .codex/spec-manifest.json 2>/dev/null || true
  fi

  # Regenerate Codex adapter skills from the freshly-synced Claude skills
  # (generated adapters carry a marker; hand-written natives are never touched).
  [ -f bin/codex-sync-skills.sh ] && bash bin/codex-sync-skills.sh >/dev/null 2>&1 || true

  # Restore org-owned skills (egregore.json → owned_skills[]) before committing.
  # On a name collision the org's committed version wins; the script reports it.
  bash bin/restore-owned-skills.sh || true

  # Show what changed
  git diff --stat HEAD
fi

Framework paths synced: bin/, .claude/commands/, .claude/skills/, .claude/hooks/, .claude/context/, .claude/agents/, .pi/, loom/, CLAUDE.md, skills/ Regenerated: AGENTS.md + .codex/spec-manifest.json via bin/codex-render-spec.mjs, then .pi/APPEND_SYSTEM.md + .pi/spec-manifest.json via bin/pi-render-spec.mjs, then the generated Codex adapter skills via bin/codex-sync-skills.sh, so all derived harnesses stay aligned with CLAUDE.md and the canonical skills. Never touched: egregore.json, .env, memory/, .egregore-state.json, .mcp.json Org-owned skills: names in egregore.jsonowned_skills[] are restored from the org's committed state after the overlay (bin/restore-owned-skills.sh) — upstream never overwrites them; collisions are reported instead.

Step 3: Post-update migrations

After syncing, run bin/post-update.sh if it exists. In worktrees, run from $MAIN_DIR to ensure the updated version executes even if the rebase didn't complete.

if [ "$IN_WORKTREE" = "true" ]; then
  [ -x "$MAIN_DIR/bin/post-update.sh" ] && bash "$MAIN_DIR/bin/post-update.sh"
else
  [ -x bin/post-update.sh ] && bash bin/post-update.sh
fi

Step 4: Commit and switch back (non-worktree only)

Worktree path already committed in Step 2. This handles the non-worktree case:

if [ "$IN_WORKTREE" = "false" ]; then
  git add -A .claude/ .pi/ bin/ loom/ CLAUDE.md skills/ AGENTS.md .codex/spec-manifest.json 2>/dev/null
  if ! git diff --cached --quiet 2>/dev/null; then
    EGREGORE_FRAMEWORK_UPDATE=1 git commit -m "Update Egregore framework from upstream"
    git push origin "$BASE_BRANCH" --quiet 2>/dev/null || true
  fi

  # Switch back to working branch, rebase, restore user's work
  if [ "$SWITCHED" = "true" ]; then
    git checkout "$CURRENT_BRANCH" --quiet 2>/dev/null
    if ! git rebase "$BASE_BRANCH" --quiet 2>/dev/null; then
      git rebase --abort 2>/dev/null || true
      echo "⚠ Rebase had conflicts — aborted. Run: git rebase $BASE_BRANCH and resolve manually."
    fi
    git stash pop --quiet 2>/dev/null || true
  fi
fi

The EGREGORE_FRAMEWORK_UPDATE=1 marker tells the branch guard this is safe on the base branch.

Step 5: Pull repos

Run /pull logic (sync base branch, rebase working branch, pull memory).

Example (on main, no worktree)

> /update

Syncing framework from upstream...
  bin/activity-data.sh         | 89 +++++------
  .claude/skills/handoff/      | new
  bin/post-update.sh           | 12 +++---
  3 files changed, 32 insertions(+), 22 deletions(-)

Running post-update migrations...
  ✓ Removed .claude/commands/ (migrated to skills)

  ✓ Framework updated and committed to main

Pulling...
  main           ✓ synced
  memory         ✓ up to date

Example (on working branch in worktree)

> /update

Syncing framework in main repo (on develop)...
  bin/notify.sh                | 12 +++---
  .claude/skills/update/       | modified
  2 files changed, 18 insertions(+), 6 deletions(-)

  ✓ Framework updated and committed to develop
  ✓ Rebased working branch onto develop

Pulling...
  develop        ✓ synced
  memory         ✓ up to date

If framework is already current

Syncing framework from upstream...
  ✓ Already up to date

Signals

GitHub stars
288
Forks
21
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
update-egregore-labs
Source
github.com/egregore-labs/egregore