sync-profile-readme
Keep the project table in a GitHub profile README in step with the account's
pinned repositories. One job: rewrite the rows inside a marked region. It does
not manage pins, write repo descriptions, or edit anything else in the README.
Path the user gave, if any: $ARGUMENTS
The row model
Every row in the managed table is one of three kinds, and the difference is a
single HTML comment that GitHub never renders:
| Kind |
Marked with |
On every run |
| Generated |
<!-- synced --> |
Rewritten from the repo's GitHub description |
| Hand-written |
nothing |
Left exactly as written |
| Unpinned |
either |
Kept in place and reported — never deleted |
The marker goes on the rows the tool wrote, not on the ones the human wrote,
so the safe default is "don't touch it": forgetting a marker can never cost
someone their prose, and the annotation sits on the row it governs rather than
in a companion file that drifts out of sync. To take ownership of a generated
row, rewrite its text and delete the marker; to hand it back, delete the row and
re-run.
Instructions
Run the dry run. It writes nothing.
"${CLAUDE_SKILL_DIR}/scripts/sync-profile-readme.sh"
Add --readme {path} when the user named a repo or README, or when the
session is not inside the profile repo. Add --user {login} only to target
an account other than the authenticated one.
Read the plan back to the user, then show the diff verbatim. Call out by
name, in plain language:
- rows being added because a repo was newly pinned,
- rows being refreshed because a description changed upstream,
- any repo in the table but no longer pinned — say it is being kept and
that removing it is their call, not the tool's,
- every
warn line (archived repo, missing description, duplicate row).
Stop and get confirmation. Never apply without it. If the run reports
RESULT: no-changes, say so and stop — there is nothing to confirm.
Apply, once confirmed:
"${CLAUDE_SKILL_DIR}/scripts/sync-profile-readme.sh" --write
Repeat any --readme / --user flags from step 1.
Report what changed and leave the commit to the user unless they ask for
one. A second run must print RESULT: no-changes — if it does not, something
is wrong; say so rather than running it again.
When it stops
Each failure names its own fix; relay it rather than working around it.
| Message |
What the user does |
gh not installed / not authenticated |
Install the GitHub CLI, run gh auth login |
| needs bash 4 or newer |
Stock macOS ships bash 3.2 — brew install bash and run it with that |
| not in the profile repo |
cd into the {login}/{login} clone, or pass --readme |
| no managed region |
Add the two markers around the table (the error prints them) |
| no pinned repositories |
Pin repos on the GitHub profile page, then re-run |
| region contains prose |
Move the prose outside the markers — this manages a table |
Do not add the markers, create the README, or restructure someone's file
uninvited. Show them where the markers go and let them place them.
Notes
- Pinned repositories are only available through the GraphQL API. The REST
API has no pinned-items endpoint, so there is no simpler call to fall back to.
GitHub caps pins at 6.
- Everything outside the markers is copied through byte for byte. The table's
header and separator rows live inside the region and are preserved verbatim,
so a customized column heading survives — do not move them above the start
marker, which would make the region unparseable.
- A repo's GitHub description is the source of truth for generated rows. If a
row's wording is wrong, fix the repo's About field and re-run; hand-edit the
row only when it deserves prose the description should not carry.
- Rows are matched by the repo URL — owner and name, not the link text — so a
row that labels
AudioFY-Data as "AudioFY" is still recognized as that repo's
row, and a same-named repo under another owner is never mistaken for it. A
custom label survives only on a hand-written row; a generated row's label is
always the repo name.
- Row order is never shuffled. Existing rows stay put; a newly pinned repo is
appended after the last pinned row.
1---2name: sync-profile-readme3description: Regenerate the project table in a GitHub profile README from your pinned repositories, so repo descriptions stay the single source of truth and the profile stops needing hand-maintenance. Use whenever the user wants to sync, refresh, or update their profile README, says "update my profile README", "my pinned repos changed", "regenerate the projects table", or "my profile table is stale", or has just pinned, unpinned, published, or re-described a repo. Reads pins through the GitHub GraphQL API (the REST API does not expose pinned items), rewrites only the region between the PROJECTS:START and PROJECTS:END markers, never rewrites a hand-written row, never deletes a row, and always shows a diff for confirmation before writing.4---56# sync-profile-readme78Keep the project table in a GitHub profile README in step with the account's9pinned repositories. One job: rewrite the rows inside a marked region. It does10not manage pins, write repo descriptions, or edit anything else in the README.1112Path the user gave, if any: $ARGUMENTS1314## The row model1516Every row in the managed table is one of three kinds, and the difference is a17single HTML comment that GitHub never renders:1819| Kind | Marked with | On every run |20| :--- | :---------- | :----------- |21| **Generated** | `<!-- synced -->` | Rewritten from the repo's GitHub description |22| **Hand-written** | nothing | Left exactly as written |23| **Unpinned** | either | Kept in place and reported — never deleted |2425The marker goes on the rows the tool *wrote*, not on the ones the human wrote,26so the safe default is "don't touch it": forgetting a marker can never cost27someone their prose, and the annotation sits on the row it governs rather than28in a companion file that drifts out of sync. To take ownership of a generated29row, rewrite its text and delete the marker; to hand it back, delete the row and30re-run.3132## Instructions33341. **Run the dry run.** It writes nothing.3536 ```bash37 "${CLAUDE_SKILL_DIR}/scripts/sync-profile-readme.sh"38 ```3940 Add `--readme {path}` when the user named a repo or README, or when the41 session is not inside the profile repo. Add `--user {login}` only to target42 an account other than the authenticated one.43442. **Read the plan back to the user**, then show the diff verbatim. Call out by45 name, in plain language:46 - rows being **added** because a repo was newly pinned,47 - rows being **refreshed** because a description changed upstream,48 - any repo **in the table but no longer pinned** — say it is being kept and49 that removing it is their call, not the tool's,50 - every `warn` line (archived repo, missing description, duplicate row).51523. **Stop and get confirmation.** Never apply without it. If the run reports53 `RESULT: no-changes`, say so and stop — there is nothing to confirm.54554. **Apply**, once confirmed:5657 ```bash58 "${CLAUDE_SKILL_DIR}/scripts/sync-profile-readme.sh" --write59 ```6061 Repeat any `--readme` / `--user` flags from step 1.62635. **Report** what changed and leave the commit to the user unless they ask for64 one. A second run must print `RESULT: no-changes` — if it does not, something65 is wrong; say so rather than running it again.6667## When it stops6869Each failure names its own fix; relay it rather than working around it.7071| Message | What the user does |72| :------ | :----------------- |73| `gh` not installed / not authenticated | Install the GitHub CLI, run `gh auth login` |74| needs bash 4 or newer | Stock macOS ships bash 3.2 — `brew install bash` and run it with that |75| not in the profile repo | `cd` into the `{login}/{login}` clone, or pass `--readme` |76| no managed region | Add the two markers around the table (the error prints them) |77| no pinned repositories | Pin repos on the GitHub profile page, then re-run |78| region contains prose | Move the prose outside the markers — this manages a table |7980Do not add the markers, create the README, or restructure someone's file81uninvited. Show them where the markers go and let them place them.8283## Notes8485- Pinned repositories are only available through the **GraphQL** API. The REST86 API has no pinned-items endpoint, so there is no simpler call to fall back to.87 GitHub caps pins at 6.88- Everything outside the markers is copied through byte for byte. The table's89 header and separator rows live *inside* the region and are preserved verbatim,90 so a customized column heading survives — do not move them above the start91 marker, which would make the region unparseable.92- A repo's GitHub description is the source of truth for generated rows. If a93 row's wording is wrong, fix the repo's About field and re-run; hand-edit the94 row only when it deserves prose the description should not carry.95- Rows are matched by the repo URL — owner and name, not the link text — so a96 row that labels `AudioFY-Data` as "AudioFY" is still recognized as that repo's97 row, and a same-named repo under another owner is never mistaken for it. A98 custom label survives only on a hand-written row; a generated row's label is99 always the repo name.100- Row order is never shuffled. Existing rows stay put; a newly pinned repo is101 appended after the last pinned row.