Skip to content

Add aperio-sync skill for keeping local main current#42

Merged
dcoln25-writer merged 7 commits into
mainfrom
droid/aperio-sync-skill
Jun 7, 2026
Merged

Add aperio-sync skill for keeping local main current#42
dcoln25-writer merged 7 commits into
mainfrom
droid/aperio-sync-skill

Conversation

@dcoln25-writer
Copy link
Copy Markdown
Contributor

Add aperio-sync skill to keep local main in sync with origin/main

Adds a Factory droid skill under .factory/skills/aperio-sync/ plus a portable, self-locating bash script and scheduler templates for macOS, Linux, and cron.

What's included

.factory/skills/aperio-sync/
├── SKILL.md                                      # Droid skill definition + install docs
└── scripts/
    ├── sync.sh                                   # the actual sync script (executable)
    ├── com.aperio.sync.plist.template            # macOS LaunchAgent (hourly)
    ├── aperio-sync.service.template              # Linux systemd user service
    └── aperio-sync.timer.template                # Linux systemd user timer (hourly)

Behaviour

The script is non-destructive by design:

  1. Resolves the repository root from its own filesystem location (<repo>/.factory/skills/aperio-sync/scripts/sync.sh<repo>), so it works from any clone path without hardcoded usernames or directories.
  2. git fetch --prune --tags origin
  3. If main is not the current branch, updates the local main ref directly via git fetch origin main:main — this refspec refuses non-fast-forward updates, so divergent history surfaces as a clear error instead of being clobbered.
  4. If main is the current branch, runs git pull --ff-only — uncommitted changes and divergence both fail loudly.
  5. Logs a one-line summary: already up to date or fast-forwarded abc1234 -> def5678 (N commits).

Never force-pushes. Never resets. Never touches your working tree when you're on a feature branch.

Smoke-tested locally

Run from outside the repo (/tmp):

$ bash /Users/<you>/repos/Aperio/.factory/skills/aperio-sync/scripts/sync.sh
From https://github.com/writer/Aperio
 * [new branch]      droid/tenant-isolation -> origin/droid/tenant-isolation
aperio-sync: already up to date at 22b1bea on branch main

Run on a stale clone (111 commits behind):

aperio-sync: fast-forwarded main be8f4a0 -> 22b1bea (111 commits)

Manual usage

.factory/skills/aperio-sync/scripts/sync.sh

Hourly schedule (macOS)

TEMPLATE=".factory/skills/aperio-sync/scripts/com.aperio.sync.plist.template"
TARGET="$HOME/Library/LaunchAgents/com.aperio.sync.plist"

sed \
  -e "s|__SCRIPT_PATH__|$(pwd)/.factory/skills/aperio-sync/scripts/sync.sh|g" \
  -e "s|__LOG_DIR__|$HOME/Library/Logs|g" \
  -e "s|__HOME__|$HOME|g" \
  "$TEMPLATE" > "$TARGET"

launchctl load -w "$TARGET"

Logs land at ~/Library/Logs/aperio-sync.log and ~/Library/Logs/aperio-sync.err.log.

Hourly schedule (Linux, systemd user timer)

See the Scheduled invocation section of the SKILL.md for the systemd snippet.

Droid integration

The description in the SKILL frontmatter is keyword-matched by the Factory droid runtime. Anytime a user says "pull / refresh / update / sync the Aperio repo" — or starts work in this repo with stale main — Droid will invoke this skill and run the script.

A self-locating bash script under .factory/skills/aperio-sync/scripts/
that fast-forwards the local main branch to origin/main without touching
the working tree or any feature branch. Refuses non-fast-forward updates
and clobbers nothing.

Ships with macOS (launchd) and Linux (systemd user timer) templates plus
a cron fallback so the sync can run hourly without manual intervention.

The Factory SKILL.md frontmatter makes Droid invoke this whenever the
user asks to pull / refresh / update / sync the Aperio repo.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
@factory-droid
Copy link
Copy Markdown
Contributor

factory-droid Bot commented Jun 6, 2026

Droid finished @dcoln25-writer's task —— View job


Security Review

Code Review

Reviewed 4 candidate findings for the new aperio-sync skill and posted 3 actionable comments:

  • [P1] systemd unit logs to ~/.local/state, a directory neither the install steps nor systemd create, so the oneshot service fails to start and the scheduled sync silently never runs.
  • [P2] [[ ! -d "${repo}/.git" ]] gives a false "not a git repository" error in git worktrees/submodules, where .git is a file rather than a directory.
  • [P2] 2>&1 on the git fetches routes git's diagnostics/errors into stdout, breaking the documented stdout/stderr log separation the skill is built around (and the redirect is unnecessary given the if ! check).

One cosmetic [P3] about the inaccurate Documentation= URL was dropped as non-actionable (systemd never acts on that field).

The skill is otherwise well-scoped and non-destructive — fast-forward-only semantics, safe quoting, and set -euo pipefail all hold, with no security issues found.

Comment thread .factory/skills/aperio-sync/scripts/aperio-sync.service.template
Comment thread .factory/skills/aperio-sync/scripts/sync.sh Outdated
Comment thread .factory/skills/aperio-sync/scripts/sync.sh Outdated
@factory-droid
Copy link
Copy Markdown
Contributor

factory-droid Bot commented Jun 6, 2026

Droid finished @dcoln25-writer's task —— View job


Security Review

Validation complete for PR #42

Reviewed all 3 candidate findings against the full diff and existing PR discussion. Approved and posted 3 inline comments: the "any working directory" invocation is broken, the macOS sed templating corrupts paths containing &, and git fetch origin main:main fails when main is checked out in another worktree.

No approved item duplicated an existing PR comment.

Comment thread .factory/skills/aperio-sync/SKILL.md Outdated
Comment thread .factory/skills/aperio-sync/scripts/com.aperio.sync.plist.template Outdated
Comment thread .factory/skills/aperio-sync/scripts/sync.sh Outdated
P1 systemd: ~/.local/state never created. install-systemd.sh now mkdir
   -ps it (and ~/.config/systemd/user) before installing the unit files.

P2 sed escape: replace-text wasn't escaped, so paths containing & or |
   corrupted the generated plist. install-launchd.sh now generates the
   plist programmatically via python3 plistlib instead of sed-templating
   XML, which sidesteps both sed-replacement escape and XML entity
   encoding (verified with a /tmp/R&D Test/ stress test; xmllint and
   plutil -lint both pass and the path round-trips bit-exact through
   plistlib.load). install-systemd.sh uses an explicit sed_escape that
   handles backslash, & and | for the systemd unit file (which doesn't
   need XML escaping).

P2 worktree detection: replace the [[ ! -d "${repo}/.git" ]] check
   (false-negative in linked worktrees and submodules where .git is a
   file) with git -C ${repo} rev-parse --is-inside-work-tree.

P2 stdout/stderr separation: drop 2>&1 on both git fetch invocations so
   git's progress and failure reasons stay on stderr where the launchd
   and systemd log routing expects them. The if ! ... check still
   detects non-zero exit codes.

P2 worktree-aware main handling: enumerate git worktree list --porcelain
   and if main is checked out in any worktree, run git -C <that wt> pull
   --ff-only there instead of trying to update a checked-out ref. This
   makes the advertised feature-branch-while-updating-main flow work for
   the standard multi-worktree setup.

P2 cwd-dependent docs: drop the git rev-parse --show-toplevel snippets
   that fail when run from /tmp. SKILL.md now requires an explicit cd
   into the clone before any command, and the schedule install path is
   reduced to running install-launchd.sh / install-systemd.sh, which
   self-locate from $0.

Also: quote __SCRIPT_PATH__ in the systemd service template so clone
paths containing spaces don't get split into multiple ExecStart args.

Drop com.aperio.sync.plist.template (no longer used now that the
installer generates the plist via plistlib).

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
@factory-droid
Copy link
Copy Markdown
Contributor

factory-droid Bot commented Jun 7, 2026

Droid finished @dcoln25-writer's task —— View job


Security Review

Validation complete for PR #42

Validated all 3 candidate findings against the full diff and existing PR discussion; all 3 were approved as actionable and non-duplicative, and all 3 were posted in a single batched review.

Approved findings:

  • dirty main worktree can still be fast-forwarded by git pull --ff-only
  • systemd unit still hard-codes %h/.local/state instead of honoring XDG_STATE_HOME
  • cron fallback writes an unquoted repo path, breaking clones with spaces/metacharacters

Comment thread .factory/skills/aperio-sync/scripts/sync.sh
Comment thread .factory/skills/aperio-sync/scripts/aperio-sync.service.template
Comment thread .factory/skills/aperio-sync/SKILL.md
@factory-droid
Copy link
Copy Markdown
Contributor

factory-droid Bot commented Jun 7, 2026

Droid finished @dcoln25-writer's task —— View job


Security Review

Validation complete for PR #42

Reviewed all 1 candidate against the full diff and existing PR discussion. Approved and posted 1 non-duplicative inline comment: the Linux systemd installer still mishandles legal clone paths containing a double quote, which can leave the generated unit unloadable.

Saved the structured validation result to /home/runner/work/_temp/droid-prompts/review_validated.json.

Comment thread .factory/skills/aperio-sync/scripts/install-systemd.sh Outdated
@factory-droid
Copy link
Copy Markdown
Contributor

factory-droid Bot commented Jun 7, 2026

Droid finished @dcoln25-writer's task —— View job


Security Review

Validation complete for PR #42

Validated all 2 candidates against the full diff and existing PR discussion. Both findings are actionable and non-duplicative, and both were posted in a single batched review.

Saved the structured result to /home/runner/work/_temp/droid-prompts/review_validated.json.

Comment thread .factory/skills/aperio-sync/scripts/sync.sh
Comment thread .factory/skills/aperio-sync/SKILL.md Outdated
dcoln25-writer and others added 2 commits June 6, 2026 21:22
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
@factory-droid
Copy link
Copy Markdown
Contributor

factory-droid Bot commented Jun 7, 2026

Droid finished @dcoln25-writer's task —— View job


Security Review

Validation complete for PR #42

Validated all 2 candidates against the full diff and existing PR discussion. Both were approved as actionable and non-duplicative enough to post in a single batched review: one catches stale origin/main reuse when recreating a missing local branch, and the other catches raw % in the generated systemd ExecStart= path.

Saved the structured result to /home/runner/work/_temp/droid-prompts/review_validated.json.

Comment thread .factory/skills/aperio-sync/scripts/sync.sh
Comment thread .factory/skills/aperio-sync/scripts/install-systemd.sh
@dcoln25-writer dcoln25-writer merged commit 2854c11 into main Jun 7, 2026
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant