# Aperio Sync

> Keep the local clone of this Aperio repository in sync with origin/main. Use whenever the user asks to pull, refresh, update, or sync the Aperio repo, or when working in the repo and the local main branch may be stale.

- Skill: `writer/aperio-sync` (Agent Skill, multi-file: 6 files)
- Install (CLI): `npx skillmds@latest add writer/aperio-sync`
- Raw SKILL.md: https://api.skillmd.com/api/skills/writer/aperio-sync/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: writer (https://skillmd.com/u/writer)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/writer/aperio-sync

---


# Aperio sync

## Purpose

Keep the local clone of this Aperio repository continuously aligned with `origin/main`. The skill does a safe, non-destructive fetch + fast-forward update — it never rewrites history, never touches uncommitted work, and never overwrites a checked-out feature branch. It is also worktree-aware: if `main` is checked out in another `git worktree`, the script fast-forwards that worktree instead of trying to update a checked-out ref.

## When to use this skill

Invoke whenever:

- The user asks to **pull**, **refresh**, **update**, or **sync** the Aperio repo.
- The user mentions that someone else (or a CI bot) pushed to `origin`.
- The user starts a new task inside the repo and the local `main` may be stale.
- The user reports "git pull", "behind origin", or "out of date" symptoms locally.
- A scheduled launchd / systemd job triggers (see [Scheduled invocation](#scheduled-invocation) below).

Do NOT use this skill to:

- Push local commits to GitHub (do that explicitly via PR workflows).
- Resolve merge conflicts (the script refuses non-fast-forward updates and surfaces them for manual handling).
- Mirror anything from a separate upstream into this repo.

## How it works

The companion script `scripts/sync.sh` performs:

1. Resolves the repository root from its own filesystem location, so it works in any clone (including linked worktrees) without hardcoded paths.
2. Verifies the resolved path with `git rev-parse --is-inside-work-tree` (this also succeeds in worktrees where `.git` is a file rather than a directory).
3. `git fetch --prune --tags origin`
4. Enumerates `git worktree list --porcelain` to find any worktree that currently has `main` checked out.
   - If one exists, runs `git -C <that worktree> pull --ff-only origin main` there.
   - Otherwise, runs `git fetch origin main:main` to update the local `main` ref directly — this refspec **refuses non-fast-forward updates**, so divergent history surfaces as a clear error.
5. Logs a one-line summary on stdout (`already up to date` or `fast-forwarded abc1234 -> def5678 (N commits)`). Git's own progress and any failure reasons stay on stderr, so launchd / systemd log routing works as advertised.

The script is idempotent — running it twice in a row is safe. It never force-pushes, never resets, never touches your working tree on other branches.

## Inputs

- None. The script discovers the repo root from its own filesystem location.

## Outputs

- Stdout: a one-line "already up to date" message, or a "fast-forwarded `abc1234` → `def5678` (N commits)" summary.
- Stderr: git's own fetch/pull diagnostics, plus any failure message.
- Exit code `0` on success or "already up to date".
- Exit code `1` if the remote is unreachable, the fast-forward pull fails because of uncommitted changes, or the update would not be a fast-forward (history diverged).

## Manual invocation

`cd` into your Aperio clone first, then run the script with its repo-relative path:

```bash
cd /path/to/your/Aperio
.factory/skills/aperio-sync/scripts/sync.sh
```

The script self-locates regardless of the caller's current directory, so passing the absolute path from anywhere also works:

```bash
bash "/path/to/your/Aperio/.factory/skills/aperio-sync/scripts/sync.sh"
```

## Scheduled invocation

Two installers are provided. Both compute the script path from their own filesystem location, escape `&`/`\`/`|` in paths before templating, create the directories systemd/launchd will not create on their own, and are safe to re-run.

### macOS (launchd, hourly)

```bash
cd /path/to/your/Aperio
.factory/skills/aperio-sync/scripts/install-launchd.sh
```

This installs `~/Library/LaunchAgents/com.aperio.sync.plist` and loads it. Logs land at `~/Library/Logs/aperio-sync.log` (stdout, sync summaries) and `~/Library/Logs/aperio-sync.err.log` (stderr, git diagnostics and failures).

Uninstall:

```bash
launchctl unload -w ~/Library/LaunchAgents/com.aperio.sync.plist
rm ~/Library/LaunchAgents/com.aperio.sync.plist
```

### Linux (systemd user timer, hourly)

```bash
cd /path/to/your/Aperio
.factory/skills/aperio-sync/scripts/install-systemd.sh
```

This creates `~/.local/state/` if needed (systemd does not auto-create parent directories for `StandardOutput=append:` targets), installs `~/.config/systemd/user/aperio-sync.{service,timer}`, reloads the user daemon, and enables the timer. Logs land at `~/.local/state/aperio-sync.log` and `~/.local/state/aperio-sync.err.log` (or `$XDG_STATE_HOME` if set).

Check status:

```bash
systemctl --user status aperio-sync.timer
journalctl --user -u aperio-sync.service
```

Uninstall:

```bash
systemctl --user disable --now aperio-sync.timer
rm ~/.config/systemd/user/aperio-sync.{service,timer}
```

### cron (portable fallback)

```bash
cd /path/to/your/Aperio
( crontab -l 2>/dev/null; \
  echo "0 * * * * /bin/bash $(pwd)/.factory/skills/aperio-sync/scripts/sync.sh >> $HOME/.aperio-sync.log 2>&1" \
) | crontab -
```

## When invoked by Droid

Run the script, then summarize the result in 1–2 lines: whether the repo was already up to date, or how many commits were pulled and the new HEAD SHA. If the script exits non-zero, surface the exact stderr so the user knows whether it was a network issue, uncommitted changes, divergent history, or a fast-forward failure in a worktree.

