aeon-update
Pull framework updates from the upstream Aeon repo into this instance - 3-way merges canon's new commits into a PR, never clobbering operator config.
git clone --depth 1 https://github.com/aeonfun/aeon /tmp/aeon-update && cp -r /tmp/aeon-update/skills/aeon-update ~/.claude/skills/aeon-updateSKILL.md
> **${var}** — mode selector; space-separated tokens, order-independent, all optional:
> - **mode** (`sync` | `report`, default `sync`) — `sync` opens a PR with the framework changes; `report` computes the delta and notifies, mutating nothing (dry run).
> - **`repo=owner/name`** — override the upstream source repo (else auto-resolved from this instance's `parent`, falling back to `aeonfun/aeon`).
> - **`reset=<sha|fork-point>`** — force the stored baseline to `<sha>` (or the merge-base with upstream) before running. Recovery / backfill lever.
>
> Empty ⇒ **sync** from the auto-resolved upstream. Examples: `` · `report` · `repo=aeonfun/aeon` · `reset=fork-point`.
Today is ${today}. This is the fleet's **downstream updater** - the counterpart to `fork-fleet`. `fork-fleet` looks *outward* from the parent to find work in the forks worth pulling *up*; this skill runs *inside* an instance and pulls the parent's shipped framework changes *down* - new skills, script/harness fixes, workflow and doc updates - and lands them as a reviewable PR. It is how an instance stays current with `aeonfun/aeon` without a hand-run rsync-overlay rebase.
## Operating principles
- **PR, never push to `main`.** Every framework change ships as one reviewable PR. The operator merges.
- **Never clobber operator config.** `aeon.yml`, `STRATEGY.md`, `soul/`, `memory/`, `output/`, `.mcp.json` and the git-derived catalogs are instance-owned. Upstream changes to them are **surfaced for manual review in the PR body**, never written into the tree.
- **3-way, not blind overwrite.** A framework file the operator has already customized is **auto-merged** when its local edits and upstream's edits touch disjoint regions (a real `git merge-file` 3-way, S6); it is only listed as a **conflict** for a human when the same lines changed on both sides. This is what lets a hand-narrowed workflow keep receiving unrelated upstream fixes without a manual merge every run.
- **Silent when in sync.** Baseline == upstream HEAD ⇒ nothing to do, no notification.
- **The baseline is the watermark, and it advances by merge.** The new baseline SHA is written *into the PR branch*, so the watermark only moves when the operator merges the PR. Unresolved conflicts are tracked separately so advancing the baseline can never silently drop them.
---
## Steps
### S0. Bootstrap + load state
```bash
mkdir -p memory/topics
[ -f memory/topics/aeon-update-state.json ] || echo '{"baseline_sha":null,"upstream":null,"last_run":null,"last_pr":null,"pending_conflicts":[]}' > memory/topics/aeon-update-state.json
```
Read `memory/MEMORY.md` for context and scan the last ~3 days of `memory/logs/` - drop anything already reported so a repeat run isn't re-sent. Read the state file:
- `BASELINE` = `.baseline_sha` (the upstream commit this instance was last synced to).
- `PENDING` = `.pending_conflicts` (files surfaced as conflicts in a prior run, not yet resolved).
### S1. Parse `${var}`
- `MODE` = `report` if the token `report` (or `dry`) is present, else `sync`.
- `REPO_OVERRIDE` = value of a `repo=owner/name` token, if any.
- `RESET` = value of a `reset=` token, if any (`fork-point` or a 7-40 char SHA).
### S2. Resolve the upstream source
```bash
SELF=$(gh repo view --json nameWithOwner -q .nameWithOwner)
UPSTREAM="${REPO_OVERRIDE:-$(gh api "repos/${SELF}" --jq '.parent.full_name // empty')}"
[ -z "$UPSTREAM" ] && UPSTREAM="aeonfun/aeon"
```
If `UPSTREAM` == `SELF`, this instance **is** canon - there is nothing upstream to pull. Write status `AEON_UPDATE_IS_UPSTREAM` to `memory/logs/${today}.md`, send **no** notification, and stop.
```bash
UP_DEFAULT=$(gh api "repos/${UPSTREAM}" --jq '.default_branch')
HEAD_SHA=$(gh api "repos/${UPSTREAM}/commits/${UP_DEFAULT}" --jq '.sha')
```
### S3. Establish / reset the baseline
- **`reset=fork-point`** → `BASELINE=$(gh api "repos/${UPSTREAM}/compare/${HEAD_SHA}...$(git rev-parse HEAD)" --jq '.merge_base_commit.sha')`. `reset=<sha>` → `BASELINE=<sha>`. Persist immediately to state, then continue.
- **First run (`BASELINE` null and no `reset`):** a fresh instance already carries all of canon from fork time, so there is no delta to apply - just **anchor the watermark**. Set `baseline_sha = HEAD_SHA`, write state, log `AEON_UPDATE_BASELINE_SET`, send a one-line notify (`baseline initialized at <head7>; future runs sync from here`), and stop. (To backfill everything since the fork point instead, re-run with `reset=fork-point`.)
- **`BASELINE` == `HEAD_SHA`:** in sync. Re-verify `PENDING` (S8) in case a prior conflict is now resolved, update state, log `AEON_UPDATE_IN_SYNC`, notify nothing, stop.
### S4. Compare baseline → HEAD
```bash
gh api "repos/${UPSTREAM}/compare/${BASELINE}...${HEAD_SHA}" --jq '{
ahead: .ahead_by, behind: .behind_by, status,
commits: [.commits[]? | {sha: .sha[0:7], msg: (.commit.message | split("\n")[0]), date: .commit.author.date}],
files: [.files[]? | {filename, status, previous_filename, additions, deletions}]
}' > /tmp/aeon-update-compare.json
```
Error handling:
- **404 / `status: "diverged"` with no merge base** (baseline not an ancestor of HEAD - history rewrite or unrelated repo): stop with `AEON_UPDATE_BASELINE_UNREACHABLE`; notify the operator to re-run with `reset=fork-point` or `reset=<sha>`.
- Cross-repo compare returns at most **300 files**; if `.files` looks truncated, note `files_truncated=true` in the report - the operator can run again after merging to pick up the remainder.
### S5. Partition changed files
Classify every entry in `.files` by path. A file is **OPERATOR-owned** (surfaced, never auto-written) if its path matches any of:
```
aeon.yml STRATEGY.md soul/** memory/**
output/** .mcp.json .env* aeon.db
skills.lock eyebrowlock.json catalog/*.json .claude/** (except .claude/skills/aeon/**)
apps/dashboard/outputs/**
```
Everything else is **OWNED** (a candidate for auto-apply): `sSet up and run an Aeon agent instance — get started from scratch, pick which skills to turn on or install more from packs, reschedule or change what runs, edit what an existing skill does, fix a skill that isn't firing, set the STRATEGY.md north star and soul/ voice, turn a coding-agent chat into a scheduled Aeon skill, and mine past coding-agent conversations for recurring work worth automating as a skill. Use when the user mentions Aeon, aeon.yml, an Aeon skill / instance / routine / pack, asks to schedule, enable, edit, or debug an agent that runs on a cron, or asks what of their repeated/manual work Aeon could take over.
Mention/keyword sweep on social platforms for [REPLACE: KEYWORDS] — trends, sentiment, top posts
5 concrete real-life actions, leverage-scored against open loops with specificity and anti-fluff gates
Static config-correctness linter for this instance - catches the silent-failure class (unquoted schedules, duplicate keys, unconfigured skills, mode typos, broken requires/MCP refs) that no run-based health skill can see. Notifies only on problems.
Write a publication-ready article in one of three angles - a trending long-form piece, a watched-repo thesis, or a project-through-a-lens essay. Optional Replicate hero image with --visual.
Automatically merge open PRs that have passing CI, no blocking reviews, and no conflicts
Two-mode aeon.yml workflow builder - analyze inspects URLs and emits a tiered, signal-verified skill-enablement plan plus an aeon.yml diff; enable flips slugs to enabled:true and opens a PR.
Evolve a skill by generating variations, evaluating them, and updating the best version