From unitism
Use this skill whenever the user is contributing to the frontend of `arenna-link`, `tennis-miami`, or `tennis-miami-web`. Triggers on any UI change (buttons, forms, layout, colors, spacing, icons), copy or text changes, design tweaks, or bug fixes visible to users. Also triggers on requests phrased as "I want to change...", "fix the...", "update the...", "the landing page needs...", or similar, when the session is in one of those three repos or mentions them by name. This skill keeps the person on a safe branch off `development`, auto-writes commits, and runs scope / secret / out-of-scope checks before opening a PR. It also generates paste-ready handoff messages when a change requires a different repo (backend, agent-server). Do NOT trigger on backend repos (`unitism-backend`, `arenna-backend`, `arenna-agent-server`), on Flutter/Dart business-logic changes that are not UI-visible, on CI / deploy / infrastructure config, or on documentation-only changes. Intended for team members whose primary role is not engineering (e.g., UX design, customer success) — engineers working in these repos can say "I'll handle this manually, skip the rails" to opt out mid-session.
How this skill is triggered — by the user, by Claude, or both
Slash command
/unitism:non-engineer-frontend-contributionThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
The UNITISM team has contributors whose primary role is not engineering (Asad — UX Design, Kath — Customer Success). They now ship frontend code directly via Claude rather than waiting on the CTO. This skill runs the full git flow underneath a few plain-language keywords, so they don't need to think about branches, commits, PRs, or conflict resolution. It also catches the cases where a change r...
The UNITISM team has contributors whose primary role is not engineering (Asad — UX Design, Kath — Customer Success). They now ship frontend code directly via Claude rather than waiting on the CTO. This skill runs the full git flow underneath a few plain-language keywords, so they don't need to think about branches, commits, PRs, or conflict resolution. It also catches the cases where a change really does need an engineer — and hands off cleanly instead of letting it get merged by accident.
Team members whose Claude Code install includes this skill. By default:
If one of the engineers has it installed because they're in a shared session, they can opt out by saying "skip the rails — I'll handle this manually" and this skill steps aside for the rest of the session.
The whole flow runs on three words the person types in chat:
| Keyword | What it does |
|---|---|
| (describe the change) | Claude creates a branch off development and starts working |
push | Claude commits the current changes (auto-written message) and pushes the branch to GitHub. Preview URL auto-deploys. Safe to use liberally — the branch is private. |
done or PR | Run all checks, rebase, open a PR to development, post the preview URL, then watch CI: auto-fix lint/format if it goes red, or hand off to Yuval/Yudi for anything an engineer needs to look at |
revert | Undo a merge the person themself shipped (own branches only) |
Mental model: a user's personal branch (e.g., asad/feat/new-button) is their private workspace. Pushing to it is safe — it only deploys to a private preview URL, never to a shared environment. development and master are the deploy-to-shared branches, which are never pushed to directly — only merged into via PR. The net effect: iterate freely on your branch with push, ask for review with done.
Before doing any work, verify:
development branch. If missing, STOP and emit the cross-repo handoff message (templates/cross-repo-handoff-message.md) addressed to Yuval or Yudi saying "please create a development branch in this repo."git config user.name returns a value. Use the lowercase first name as the branch prefix (e.g., "Asad Rahman" → asad). If blank, ask once and persist.push the pending work onto the existing branch first.These checks take a few seconds and prevent the two failure modes that have actually bitten us in production:
(a) long-running branches whose base has drifted weeks behind development, producing unresolvable conflicts at PR time (e.g., a branch from a month ago that touches src/lib/api.ts or src/app/admin/layout.tsx — both heavily rewritten on development since), and
(b) work done on a branch that didn't go through this skill (e.g., a claude/... branch auto-named by the claude.ai web UI, or a branch missing the {username}/ prefix).
git fetch origin
BRANCH=$(git rev-parse --abbrev-ref HEAD)
USERNAME=$(git config user.name | awk '{print tolower($1)}')
Then evaluate, in order:
master or development?If yes: do NOT do work here. Skip ahead to step 2 ("Create a branch") below and branch off fresh origin/development. Tell the user: "You were on {branch}; I'm starting a fresh branch for this change."
A skill-shaped branch matches {username}/{type}/{slug} where {type} is one of feat|fix|copy|style|chore and {username} matches the lowercase first name from git config user.name.
If the current branch does NOT match (e.g., claude/charming-ptolemy-046c58 — the auto-generated claude.ai web UI naming pattern — or feat/admin-community-updates with no username prefix, or any other manually-created branch):
{branch}, which doesn't look like it came from this skill. It might be from claude.ai's web UI or created manually. I recommend renaming it to {username}/{inferred-type}/{inferred-slug} so the PR is easy to spot in review. OK?"git branch -m {new-name} && git push origin -u {new-name} && git push origin --delete {old-name}. If only local: git branch -m {new-name}.Find how stale this branch's base is:
BASE=$(git merge-base origin/development HEAD)
BASE_AGE_DAYS=$(( ( $(date +%s) - $(git show -s --format=%ct $BASE) ) / 86400 ))
DEV_AHEAD=$(git rev-list --count HEAD..origin/development)
Thresholds:
BASE_AGE_DAYS <= 7 AND DEV_AHEAD < 20 → fresh. Continue.BASE_AGE_DAYS > 7 OR DEV_AHEAD >= 20 → stale. Tell the user: "Your branch was based on development from {BASE_AGE_DAYS} days ago, and development has moved {DEV_AHEAD} commits since. To avoid a conflict pile-up at PR time, I'm going to rebase before continuing." Then run git rebase origin/development and follow the 5a conflict path if there are conflicts.BASE_AGE_DAYS > 21 OR DEV_AHEAD >= 60 → abandoned-base risk. Tell the user: "This branch is very stale ({BASE_AGE_DAYS} days, {DEV_AHEAD} commits behind). Continuing on it is likely to produce unfixable conflicts in widely-used files (like api.ts or layout files). I recommend starting fresh: I'll cherry-pick your commits onto a new branch off latest development, and we resolve any conflicts at cherry-pick time rather than at rebase time." Wait for the user to confirm before proceeding.One feature = one branch. The default is a new branch on every fresh request — that's how a single branch ends up with 20+ unrelated changes when this rule slips.
If the user's request describes work that doesn't match the current branch's slug (e.g., user is on kath/feat/signup-button-color and now says "I want to rewrite the workflows page"), do NOT ask whether to bundle. Announce the action and the override:
"Starting a new branch for this — it doesn't sound like the same change as
signup-button-color. Saysame branchif you want to bundle them, but narrow PRs ship much faster."
Then jump to step 2.
Only ask a clarifying question if the relationship is genuinely ambiguous (e.g., "make the button bigger" while on signup-button-color is clearly the same change — no question needed; "adjust the form spacing" while on signup-button-color could go either way — one short question).
A prior session may have started watching CI on a PR but timed out before checks completed (see 5g.4). If so, it left a marker file in .git/non-engineer-skill/. Resume any such watches before doing anything else, so the user isn't left with a forgotten red CI.
WATCH_DIR=".git/non-engineer-skill"
[ -d "$WATCH_DIR" ] && ls "$WATCH_DIR"/watching-*.json 2>/dev/null
For each marker file found:
gh pr checks $PR --json state --jq '[.[].state] | unique'
SUCCESS → delete the marker, announce: "PR #$PR from your last session passed CI. Ready for review."FAILURE or ERROR → delete the marker, jump into 5g.3 (categorize and act) for that PR before continuing.IN_PROGRESS / PENDING / QUEUED → keep the marker, announce: "Your PR #$PR is still in CI from last session. I'll re-check it after your new request, or just say watch {PR} to focus on it now." Continue to step 1 — don't block the user.Only proceed to step 1 after all five pre-flight checks pass (or P5 has resolved every marker it found).
Example: "I want to change the signup button color to navy."
Ask at most one clarifying question, only if the intent is genuinely ambiguous. Good question: "Which signup button — the one on the landing page, or the one inside the app?" Bad question: "What exact hex code?" — non-engineers find over-questioning discouraging.
git fetch origin
git checkout -b {username}/{type}/{slug} origin/development
Branch naming:
{username} — lowercase first name from git config user.name{type} — one of feat, fix, copy, style, chore. Infer from intent: "change the X" → feat; "fix the Y" → fix; "reword" / "rewrite text" → copy; "adjust spacing" → style.{slug} — hyphenated short summary, max 4 words. e.g., signup-button-color, homepage-copy-v2, fix-dropdown-overflow.Announce what happened in one line: "Working on asad/feat/signup-button-color, branched from latest development."
Make the change. If there's a cheap local-verify step (dev server, storybook, visual check), do it. Do not refactor code that isn't part of the stated task — that's a direct cause of scope creep and the reason step 5b exists.
push — commit and publishOne keyword, two atomic git actions. Claude does both.
(a) Auto-write a conventional-commit message from the diff. Format:
<type>(<optional scope>): <imperative, sentence-case, ≤72 chars>
Examples:
feat(signup): change button color to navy bluefix(form): correct email validation on signup pagecopy(landing): rewrite hero subheadlineCommit with that message.
(b) Push the branch:
git push -u origin <branch>
Confirm: "Pushed to GitHub. Preview URL will appear in ~1 minute at ." Vercel/Firebase Hosting auto-deploy a preview per branch — see reference/onboarding-for-non-engineers.md for address patterns.
There is no local-only "save" concept. The branch is the safe space; pushing to it is just syncing and generating a fresh preview. Iterate freely — push as many times as needed.
(c) Base freshness nudge. After pushing, recompute BASE_AGE_DAYS and DEV_AHEAD (same commands as pre-flight P3). If BASE_AGE_DAYS > 7 OR DEV_AHEAD >= 20, nudge the user without blocking: "Heads up: this branch's base is {BASE_AGE_DAYS} days old and development has moved {DEV_AHEAD} commits since. Want me to rebase now? It's much cheaper to handle conflicts in small batches than all at once at done time." This is a nudge, not a gate — let the user keep iterating if they want.
(d) File-count nudge. After pushing, count files changed on the branch: FILES=$(git diff origin/development...HEAD --name-only | wc -l). If FILES > 5, tell the user every time (this is intentional repetition — they should not be surprised at done time):
"Heads up: this branch now touches {FILES} files. Non-engineer PRs are capped at 5 files — at
donetime I'll have to split this into separate PRs. Want to stop and split now, or keep going and split later? Splitting earlier is cheaper than splitting later."
This is a heads-up, not a gate — pushing remains friction-free. The hard enforcement happens at 5b. The point of the heads-up is to prevent the failure mode where the user does 60 files of work, hits done, and is now angry that they have to retroactively split.
done or PR — prepare and open the PRRun these checks in order. Do not skip any. If any fails, STOP and follow the failure path — do not open the PR.
developmentgit fetch origin
git rebase origin/development
If the rebase succeeds cleanly, continue to 5b.
If there are merge conflicts, inspect the conflicted files:
Safe to auto-resolve — accept origin/development's version (git checkout --theirs <file> && git add <file>) and continue the rebase:
package-lock.json, yarn.lock, pubspec.lock, Cargo.lock, poetry.lock, Gemfile.lock/generated/ or /.generated/ directories, or files whose first 3 lines contain generated / AUTO-GENERATED / DO NOT EDIT (case-insensitive)When auto-resolving, tell the user transparently: "I auto-resolved a conflict on <file> by accepting the latest version from development. Your other changes are intact — continuing."
Everything else (code, copy, config, anything that's not a lock or generated file) — STOP. Do not attempt to resolve; a wrong auto-resolve is worse than a stuck PR. Produce two outputs:
templates/cross-repo-handoff-message.md) addressed to Yuval or Yudi, listing the conflicted files and the recent development commits that caused the conflict.src/components/BookingForm.tsx — can you sort it?" Tell the user: "For simple conflicts, chat is faster than the formal handoff — use whichever feels right."Wait for the engineer to resolve before resuming.
This check has two tiers: a hard file-count cap that the user CANNOT override, and soft scope-creep signals that default to splitting but can be overridden with keep bundled + a logged justification.
FILES=$(git diff origin/development...HEAD --name-only | wc -l)
If FILES > 5: STOP. Do not open the PR. This is a hard cap for non-engineer accounts. The reasoning: 5 files is the threshold where a PR can be reviewed in one sitting without context loss. Above that, review stalls — which is exactly the failure mode this rule prevents (the May 2026 incident: two 60+ file PRs that stalled because they couldn't be reviewed coherently).
Two paths forward — pick based on whether the change is genuinely cross-cutting:
Path A (default): Split into multiple PRs. Group files into ≤5-file batches by coherent theme. For each group, create a new branch off development, cherry-pick the relevant commits, push, open a PR. Walk the user through it in plain language — non-engineers don't know what cherry-picking is, so narrate each step ("I'm taking commits X, Y, Z from your branch and putting them on a new branch called {name} — that becomes one PR. Then commits A, B become another PR. Same work, just split into reviewable chunks."). The user does not need to do anything except confirm the split plan.
Path B (rare): Cross-cutting handoff. If the change is legitimately cross-cutting and cannot be split — examples: a variable/component rename touching every importer, a theme-token migration, a translation key added to every locale file, a dependency bump touching every consumer — STOP and emit the cross-repo handoff message to Yuval or Yudi. Tell the user: "This looks like a cross-cutting change that can't be split into ≤5-file PRs. I'm handing off to Yuval or Yudi — they'll either take over the PR or confirm an exception." The user CANNOT self-approve a cap exception. Only an engineer can. This prevents the override from being abused by non-engineers who'd rather not split.
Even at ≤5 files, look at the diff for these signals:
If a signal fires: STOP. Default to splitting. Tell the user:
"This branch is at {FILES} files (under the cap), but the changes span
{list of areas}. I'd split this into separate PRs — one per coherent group — so each reviews quickly. Here's the split plan: {groups → files}. Saykeep bundledonly if these truly belong together as one logical change."
If keep bundled, accept it but log the justification in the PR body's "## What changed" section. Otherwise, execute the split using the same procedure as Path A above.
| File count | Scope-creep signal | Default action | Override? |
|---|---|---|---|
| ≤5 | none | open one PR | — |
| ≤5 | yes | split | keep bundled with logged reason |
| >5 | — | split (Path A) or handoff (Path B) | engineer-approved only, never user |
Scan the diff for signals that this change requires a different repo / backend work to actually function.
Data and APIs:
.env.example or config schemasAnything that happens after the user clicks:
General rule that covers the above and anything not listed:
If the change involves anything that happens after the user clicks — an email sent, a payment processed, data persisted, a notification delivered, a permission enforced — treat it as out of scope. Frontend only owns what the user sees and types.
If any signal fires: STOP. Do not open the PR. Fill in templates/cross-repo-handoff-message.md with the specifics and show it to the user. Tell them:
This change needs a backend change first. Here's a message to send to Yuval or Yudi — copy it as-is into your chat with them. When they say it's done, come back here and say
doneagain and I'll continue.
Grep the diff for common leak patterns:
sk-, pk_live_, pk_test_, AIza, xoxb-, ghp_, github_pat_.env files added to the commit[A-Za-z0-9]{32,} inside files that aren't lockfiles, snapshots, or build outputspassword=, secret=, token=, api_key= followed by non-placeholder valuesIf any match: STOP. Do not push. Offer to amend the commit to remove the secret and rotate it via Yuval or Yudi. Say clearly what was found and where.
gh pr create \
--base development \
--title "<slug rewritten as sentence>" \
--body "<auto-written body>"
PR body template:
## What changed
<one paragraph — what the user asked for, what ended up in the diff>
## Preview
<preview URL from Vercel or Firebase preview channel>
## Visual check
- [ ] Opened the preview URL
- [ ] Looks right on desktop
- [ ] Looks right on mobile
## Review
First responder wins (Yuval or Yudi).
---
Requested by {username} via `non-engineer-frontend-contribution` skill.
Print the PR URL. Emit a one-liner the person can paste into the team chat:
{username}opened a PR in{repo}:{title}— {PR URL}
Don't disengage at PR open. Closing the loop is the whole point — without this step, the non-engineer is left staring at a red X in GitHub with no idea what to do, and pings Yuval or Yudi anyway.
Immediately after notifying, announce:
"PR opened at {URL}. Watching CI checks now — I'll auto-fix lint or format issues if any come up, or hand off to Yuval/Yudi if it's something an engineer needs to look at."
Run with a 20-minute timeout:
timeout 1200 gh pr checks <pr-number> --watch --interval 30 --required
EXIT=$?
Three possible outcomes:
EXIT=0 → all required checks passed → continue to 5g.2 (all green)EXIT=8 → at least one required check failed → continue to 5g.3 (categorize)EXIT=124 → timed out after 20 min → continue to 5g.4 (long-wait fallback)Confirm: "All checks green. PR is ready for review." DONE.
Pull failure details:
gh pr checks <pr-number> --json name,state,description,link \
--jq '.[] | select(.state == "FAILURE" or .state == "ERROR")'
For each failed check, sort into one of two buckets:
Auto-fixable (skill attempts; total budget: 3 fix cycles per PR):
package.json scripts, pubspec.yaml, .pre-commit-config.yaml, etc.)npm run lint -- --fix, npx prettier --write ., dart format ., etc.)git add -u && git commit -m "style: auto-fix lint" && git pushX in Y — fixing now."fix: prefix, push, return to 5g.1Handoff (skill does NOT attempt — emit cross-repo handoff message):
Enforce 5-file cap for non-engineer authors) — if this fires, the skill missed something earlier; escalate so we can find the bug.If any check falls into the handoff bucket, OR the 3-cycle auto-fix budget is exhausted: STOP. Emit the cross-repo handoff message (templates/cross-repo-handoff-message.md) naming the failing check(s), the cycle count, the auto-fix attempts made, and the PR URL. Tell the user:
"I got the PR opened but couldn't get it green on my own —
{check name}needs an engineer. Here's a message to send Yuval or Yudi. They'll either fix it directly or guide me through it."
CI legitimately takes longer than 20 minutes sometimes — Flutter builds, large test suites, deployment previews. When the watch times out with checks still pending, write a marker file so the next session in this repo auto-resumes:
mkdir -p .git/non-engineer-skill
PR=<pr-number>
BRANCH=$(git rev-parse --abbrev-ref HEAD)
TS=$(date -u +%s)
printf '{"pr": %d, "branch": "%s", "started": %d}\n' "$PR" "$BRANCH" "$TS" \
> .git/non-engineer-skill/watching-$PR.json
Tell the user:
"Checks are still running after 20 min — that's normal for big builds. GitHub will email you when they finish. The next time you open Claude in this repo, I'll auto-resume the watch and either confirm green or hand off to an engineer. You don't need to do anything."
Then exit the flow.
revert — undo a mergeOnly the branch author can revert their own branch's merge. If the user asks to revert something someone else merged, decline and emit a handoff message to Yuval or Yudi.
For the author's own merges:
git checkout development
git pull origin development
git revert -m 1 <merge-commit-sha>
git push origin development
Then notify: "Reverted. development is back to how it was before your PR. Anything you wanted to keep from it is still on your original branch — tell me and we'll try again."
master or development (always branch off)development or master (only PRs reach those branches)development yourself — always PR, always human review_shared/strategy/ai-strategy-handoff.md — terminology rule)development without rebasing first (skipping this is exactly what produced the kath/admin-panel-pages conflict pile-up in May 2026)claude/... — that's claude.ai's web UI auto-naming; treat it as a non-skill branch and run P2 renameIf the user asks for something this skill isn't built for — a config change, a CI tweak, a deploy script, a new dependency, a backend change — STOP and emit the cross-repo handoff message addressed to Yuval or Yudi. Non-engineers should not touch CI, config, infrastructure, or backend directly; the handoff flow is how those changes get made safely.
templates/cross-repo-handoff-message.md — the paste-ready format emitted on out-of-scope, conflict, or infra-adjacent requests.reference/onboarding-for-non-engineers.md — the plain-language primer Asad and Kath read before their first use, including the flow diagram.Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub yuvalklein/unitism-skills --plugin unitism