uipreliga
90d · built 2026-09-30
Performance
What uipreliga shipped in the selected window, measured in ETV, and how it compares with the 90 days before it.
Effective capacity
−0.5engineers
delivers like 0.5 (0.5x pre-AI)
Output (ETV)
4.5ETV
+3.9% vs 4.4 prior
Features share
6.2%
−30.7 pp vs prior window
Fixes share
12.4%
+6.2 pp vs prior window
Work mix
6.2% Features4.6% Maintenance16.6% Tests60.3% Docs12.4% Fixes
94 commits over 90 days, ending 2026-09-30.
Daily performance
Daily ETV, stacked by Features, Maintenance, Tests, Docs and Fixes.
Repository spread
Where this developer's commits land. Concentrated work (top1 > 80%) vs polymath spread (top1 < 30%).
Most impactful commits
Top 10 by ETV in the last 90 days.
- 0.9ETVci: make the Tier 1 / Tier 2 required-check set enablable (#3100) * ci: make the Tier 1 / Tier 2 required-check set enablable Prerequisites from the 2026-09-03 PR CI audit. No ruleset change here — the new contexts must report on a real PR before they can be required, or every open PR blocks on a pending check that never arrives. Drop the `paths:` filters that make a check unrequirable. When a filter excludes a PR the workflow never runs, no check is reported, and a required context stays pending forever. Removed from test-helpers.yml, validate-skills.yml, validate-skill-status.yml and validate-skill-flavors.yml, each carrying the rationale already used in validate-version-sync.yml and validate-skills-sh.yml. The jobs are all sub-60s; the ones that can short- circuit do so inside the job, where a skip counts as a pass. Add fixed-name aggregators to the two matrix gates. `activation-gate.yml` and `verb-gate.yml` name their gate job `${{ matrix.skill }}` — 61 distinct check names in one quarter, so no literal context can ever match. `Skill activation gate` and `CLI verb gate` roll up detect + every leg under `if: always()`. That brings ~13,000 runs/quarter of existing coverage under enforcement at no added CI cost. Resolve both check-name collisions. Two jobs sharing a context make it ambiguous which run satisfied it: verb-gate's detect job is now `Detect changed skills (CLI verb gate)`, and publish.yml's push-event guard is `Validate version sync (publish guard)` — the latter could otherwise land a same-named check on the merge commit for the already-required PR check. Keep the two detect jobs required, against the audit's recommendation. Both smoke workflows gate on `needs: detect` + `if: ...skip != 'true'`, so a detect FAILURE skips the gated job — and GitHub counts a skipped job as a pass. The repo's most expensive gate would report green having run nothing. Documented as Rule 3 and pinned by a test. docs/REQUIRED-CHECKS.md is the target set; scripts/apply-required-checks.sh parses it and PUTs the ruleset, warning about any context not seen on recent PR heads. `required-check contract guard` (test-helpers.yml) fails if a required job is renamed, regains a `paths:` filter, collides on a name, or depends on an uncovered job — the drift is otherwise invisible, since the ruleset lives in the GitHub API and nothing in the build reads the doc. Validated: actionlint and shellcheck clean on every changed file (only the pre-existing custom-runner-label warnings remain); 169 tests pass under tests/scripts/; both failure modes confirmed by negative control. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MwcGSztKjzjPbGhNCSAQQ2 * ci: close the gaps a multi-axis review found in the required-check work Three HIGH findings, all real and reproduced locally, plus five smaller ones. Give the doc table exactly ONE parser. It had two — awk in apply-required-checks.sh, a regex in the contract guard — with different tolerances. A row the script accepted but the guard dropped would be PUT to the ruleset having never been checked against the workflows; a row with an annotation in the first cell would be applied as a mangled context GitHub waits for forever, which is the "blocks every open PR" failure this whole change exists to prevent. scripts/parse-required-checks.py is now the only parser: the script shells out to it, the test imports it, and it errors on a row it cannot read instead of dropping it. Make the Rule 3 guard actually check the rollup. It short-circuited on the mere substring `always()` in a job's `if:`, so gutting a gate-summary to `run: echo ok` kept 61 tests green while the required context reported success regardless of what any leg did — the exact failure the rule describes. It now asserts the job reads each `needs.<job>.result`. Stop swallowing real failures inside two newly-required checks. verb-gate's `|| true` was only ever masking a crash (the checker returns 0 unconditionally in --json mode), and validate-skills.yml's single `|| true` over a `git diff | grep` pipeline masked a failed `git diff` as "nothing to validate". Both reported green having validated nothing; both now fail loud, demonstrated locally. Also: widen the trigger guard past `paths:` to `paths-ignore:`, `branches:`, `branches-ignore:` and a `types:` list missing `synchronize` — each starves a required context identically; reject an unexpanded `${{ }}` context, Rule 1's second documented cause, which nothing checked; replace the `>= 15` row floor with an exact count, since it let a partial parse silently drop 8 of 23 rows and shrink every parametrized suite; add `per_page=100` to the doc's pre-apply command, which already truncates at 30 on 3 of 5 open PR heads today; allow-list the two good job results in both aggregators instead of deny-listing the two bad ones, so an unrecognized value fails closed; pin validate-skill-flavors.yml's three actions to the SHAs its siblings use, now that it runs on every PR; and fix `read -r reply` aborting under `set -e` on non-tty stdin, plus a `--help` that was a hardcoded line range into its own header. Validated: 217 tests pass; actionlint and shellcheck clean on all new code; parser and guard emit byte-identical 23-context lists. Five negative controls confirm the new assertions fire — gutted aggregator, paths-ignore, dropped synchronize, half-backticked row (fails the test AND blocks the apply script), and an unexpanded expression context. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MwcGSztKjzjPbGhNCSAQQ2 * docs(claude): register REQUIRED-CHECKS.md as a same-PR registry CLAUDE.md is loaded into every agent session here; CONTRIBUTING.md is not. The same-PR rule for the required-check set was only in CONTRIBUTING.md, so an agent renaming a workflow job would never see it — and renaming a job that produces a required context blocks EVERY open PR, not just its own. Follows the pattern rule 5 already sets for assets/skill-status.json and skills.sh.json: a registry not discovered from disk gets a numbered rule with its verification commands plus a File Conventions row. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MwcGSztKjzjPbGhNCSAQQ2 * ci: guard the required aggregators with !cancelled(), not always() `always()` runs a job during run cancellation too. Both gate workflows set `cancel-in-progress: true`, and activation-gate.yml also triggers on `ready_for_review` — so taking a PR out of draft starts a second run that cancels the first on the SAME head SHA. The cancelled run's aggregator still executed, read `needs.detect.result == "cancelled"`, and reported the required context FAILED. This PR's own head carried a red `Skill activation gate` beside a green one on 1056e6c56 (runs 34055252280 and 34055306035). Nothing blocked, because the good run happened to finish last — by ~70s. Once the context is required that ordering decides whether merge is blocked. `${{ !cancelled() }}` skips the aggregator when the run is cancelled: a skipped job counts as a pass and the newer run on that SHA reports the real answer. It still runs and fails when a needed job fails, and when a leg hits timeout-minutes (a timed-out job does not cancel the run, so the result arrives as `cancelled` and the explicit check fires). The trade, documented in Rule 3: manually cancelling a run now leaves the aggregator skipped rather than failed, so write access can skip these two gates. Accepted — both are quality gates behind CODEOWNERS approval, and the alternative blocks merge at random on superseded runs. test_required_job_needs_are_covered now rejects `always()` outright instead of accepting it, and keeps demanding that the rollup actually read each `needs.<job>.result`. Both negative controls verified: reverting to `always()` fails the guard, and gutting the rollup to `echo` fails it too. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MwcGSztKjzjPbGhNCSAQQ2 * ci: catch a required job that never reaches the target-set table Rebasing this branch onto main dropped `maestro-bpmn checker unit tests` from docs/REQUIRED-CHECKS.md: the job came from main, the table row was added in the merge commit, and rebase discards merge commits. 24 contexts became 23 and all 87 tests still passed — every existing test reads the doc and checks it against the workflows, so a job missing from the table is invisible by construction. Add the reverse direction for test-helpers.yml, the one workflow where the rule is unconditional: it holds cheap, deterministic, always-run guards, so a job here that is not required has no legitimate reason to exist. Advisory or nondeterministic checks belong elsewhere (Rule 4), which is why this is not generalised to every workflow. Restores the dropped row. Negative control: deleting it again fails the new test with the job name. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MwcGSztKjzjPbGhNCSAQQ2 * ci: stop ready_for_review from cancelling a run on its own head SHA The previous commit claimed `!cancelled()` made a superseded run's aggregator report `skipped`, which counts as a pass. Measured, it does not: dispatching activation-gate.yml and cancelling it mid-flight reported cancelled Skill activation gate (run 34067126301). A job skipped by `if:` during RUN cancellation is reported `cancelled`, and `cancelled` is non-passing exactly like `failure`. So `!cancelled()` alone left the race it was meant to remove, and the trade-off noted in Rule 3 — that manual cancellation becomes a merge bypass — does not exist either. Both claims are corrected here. The real cause is two runs on one SHA. activation-gate.yml triggers on `ready_for_review`, the only event that fires on a commit a run is already in flight for, while `cancel-in-progress: true` cancelled that in-flight run. GitHub keeps the latest check run per context name, so merge turned on which of the two recorded its result last. Fix it where it happens: cancel-in-progress: ${{ github.event.action != 'ready_for_review' }} Every other event arrives with a new SHA, where cancelling is free — the superseded run's red lands on a commit nobody is merging. verb-gate.yml has no `ready_for_review` trigger and needs no change. `!cancelled()` stays on both aggregators for what it actually does: resolves the aggregator the instant a run is cancelled instead of after a runner acquisition, and keeps a bogus "could not determine which skills to gate" error out of a superseded run's log. Cost: one extra activation-gate run per draft flip. It is cheap — `gate` skips on drafts, so the run that is no longer cancelled is a detect plus a skipped matrix. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MwcGSztKjzjPbGhNCSAQQ2 * ci: close the same-SHA cancel hazard and the ruleset-clobber risk Review found the Rule 3a fix was half right. `ready_for_review` is not the only event that fires on a commit a run is already in flight for: `reopened` does too (closing a PR does not cancel its runs), and it is a default `pull_request` type — so the hazard was live on five more required workflows still carrying `cancel-in-progress: true`. Replace the deny-list with an allow-list on every required workflow: `cancel-in-progress: ${{ github.event.action == 'synchronize' }}`. Only `synchronize` moves the head SHA, so it is the only event where a superseded run's red lands on a commit nobody is merging. A new contract guard, `test_concurrency_only_cancels_on_a_new_head_sha`, enforces it. apply-required-checks.sh sent a literal body carrying only `conditions` and `rules`. Live state also carries `enforcement` and two `bypass_actors` (OrganizationAdmin, RepositoryRole 5), plus `required_reviewers` and `dismissal_restriction` the literal `pull_request` block dropped. GitHub's behaviour for omitted fields on PUT rulesets is undocumented; if omitted means cleared, the first run drops admin bypass on `main`. Build the body from the live ruleset and author only the status-check list. Also in the script: fail closed when the open-PR list or a check-run read fails (an auth error was indistinguishable from "no open PRs", which skipped the one safety check), move the count line to stderr so `--dry-run` stdout is pipeable JSON, and add `--check` — the doc-to-ruleset direction nothing else covers. Contract guard holes, each with a negative control: - `if n` dropped jobs with no `name:`, whose context is the job id — the exact direction the reverse guard was written to close - `"cancelled()" in condition` also accepted the inverse `${{ cancelled() }}`, an aggregator that skips every normal run and reports a pass - counting an `env:` mapping as consumption accepted a rollup whose `run:` is `echo ok` - `glob("*.yml")` missed a colliding job in a `.yaml` workflow - no invariant kept `ready_for_review` on activation-gate.yml, without which a PR opened as a draft is never re-gated - the uncovered-needs message recommended `always()`, which the same test rejects Cut the four-way duplication of the `!cancelled()` rationale to one canonical copy in the doc plus a pointer from each aggregator, correct the doc's "`always()` aggregator" wording, and record the accepted cost of validate-skill-flavors.yml running on GitHub-hosted minutes. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>github.com-UiPath-skills · c7837b29 · 2026-09-08
- 0.7ETVfix(ci): scope the skills.sh drift check to drift the PR introduces (#3043) * fix(ci): scope the skills.sh drift check to drift the PR introduces `Validate skills.sh.json against skills/` failed 68 times in the last three months — a 6.1% failure rate, the highest of any deterministic gate in the repo. 65 of those 68 failures were one incident. #2252 landed `skills/uipath-process-mining/` on 2026-08-04 without a `skills.sh.json` entry. The checker reads the whole tree, so from 15:52 that day until 17:13 on 2026-08-06 every PR touching any `skills/*/SKILL.md` went red for drift it did not cause — ~20 unrelated branches, 65 failed runs. The entry was finally added by an unrelated PR (#2498, a solution zip-filename fix) that happened to trip over it. The remaining 3 failures were skill-adding PRs failing legitimately. So 96% of this check's failures were false positives, which is also why it merged red 5 times: a check that cries wolf gets clicked through, and that is how the drift reached main in the first place. Fix: `--baseline-ref` compares findings against the base commit. Findings that also reproduce at the baseline print as `::warning::` and do not fail the run; only findings the change introduces exit 1. Whole-tree visibility is kept — the blast radius is not. An unreadable baseline (shallow clone, missing base) falls back to strict whole-tree behaviour, so the failure mode is the old behaviour rather than a silent pass. Replayed against the real incident: #2252 (adds process-mining) new=[uipath-process-mining] exit 1 ✓ still blocks #2436 (unrelated, maestro-case) pre-existing exit 0 ✓ no longer blocks #2498 (adds the entry) clean exit 0 ✓ Docs: `skills.sh.json` is not derived from disk, so a rename or removal leaves it stale with no symptom other than this check. CONTRIBUTING.md covered adding a skill, but it is not loaded into agent context — CLAUDE.md and `.claude/rules/` are, and neither mentioned the file. Added the add/rename/remove contract to CLAUDE.md (rule 5 + File Conventions), `.claude/rules/skill-structure.md` (new § skills.sh Grouping), `.claude/rules/pr-review.md` (both checklists), and a rename/removal subsection in CONTRIBUTING.md. Tests: `tests/scripts/test_check_skills_sh.py` (15 cases) pins the contract — pre-existing drift warns, introduced drift fails, a dirty baseline is no shield for fresh drift, renames fail on both halves, an unreadable baseline stays strict. Registered as a Test Helpers job. This also makes the check safe to add to the required set. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(ci): address review — stable finding identity, no paths filter, HEAD^1 baseline Review from @bai-uipath. All three findings reproduced and fixed. 1. Finding identity keyed on the formatted error string, which embeds grouping titles and list indices, so unrelated edits re-attributed pre-existing drift as new. Reproduced against the previous commit: retitle a grouping (duplicate drift already present) -> exit 1 insert a grouping at the top (schema drift present) -> exit 1 Findings now carry an explicit `kind` and a `subject`, and identity is `(kind, subject)`. `key`/`error` stay display-only, so output is unchanged. Coverage findings key on the skill name alone — retitling a grouping or moving a bad entry between groupings is not new drift. Schema findings key on the grouping title when it is valid, never the index. Both scenarios now exit 0, and five tests pin it. 2. Dropped the `paths:` filter. The reviewer is right that blast radius was not the only failure mode: the check never ran on #2252 at all — 19 checks reported on that head, and this was not among them — even though the workflow had existed since 2026-07-31 and the filter listed `skills/*/SKILL.md`. The guard was silent on the one PR it existed to catch. validate-version-sync.yml and smoke-rpa-skills.yml already document the required-check rationale verbatim; this workflow now matches. ~20s job, so it just always runs. A manual dispatch gets no baseline and validates the whole tree strictly. 3. Removed `fetch-depth: 0` from the new test job. Every test resolves HEAD or a deliberately missing ref, both fine on the default shallow clone. Also took both optional suggestions: - Baseline is now `HEAD^1`, the base parent of the merge commit actually under test, rather than the event payload's `base.sha`, which can lag the merge ref GitHub recomputed. Let the validate job's fetch-depth drop from 0 to 2. - CLAUDE.md rule 5 now points at the skill-structure rule for the full change→edit table instead of restating the `--fix` limits, per .claude/rules/token-optimization.md § 3 (one full statement + pointers). And the Claude review bot's finding: test_cli_json_output_carries_the_ preexisting_flag passed by vacuous truth — a clean tree emits no JSON, so the loop body never ran. Replaced with a fixture that produces one pre-existing and one introduced finding, asserting both `preexisting` values actually emit, plus a separate test that a clean tree stays silent. 21 tests, all passing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>github.com-UiPath-skills · 302e5f24 · 2026-09-03
- 0.4ETVchore(preview): re-sync Maestro SDK skills to flow-builder-sdk@4db8e12 (#2878) 🤖 Generated with Claude Code Co-Authored-By: [Claude](mailto:noreply@anthropic.com) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>github.com-UiPath-skills · b6c20cfd · 2026-08-28
- 0.4ETVchore(preview): re-sync Maestro SDK skills to flow-builder-sdk@49520ad (#2722) 🤖 Generated with Claude Code Co-Authored-By: [Claude](mailto:noreply@anthropic.com) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>github.com-UiPath-skills · 0f679f50 · 2026-08-20
- 0.3ETVfix(ci): harden catalog refresh — branch cleanup, token split, subtree-loss guard (#2398) * fix(ci): stop stranding refresh branches, split feed-read from repo-write PAT The nightly catalog refresh failed every day from 2026-06-30 to 2026-07-30. `GH_PAT` was rotated on 06-25 to a token that reads the GitHub Packages feed but cannot write labels, so `gh label create` returned `HTTP 404 .../labels` (GitHub 404s instead of 403 when a token lacks a permission). Three consequences, all fixed here: - The step died after `git push`, stranding one branch per run. 34 `auto/refresh-uip-catalog-*` branches accumulated with no open PRs. A trap now deletes the pushed branch unless a PR ended up owning it. This also removes a latent deadlock: the branch name is version + UTC date, so a same-day retry at an unchanged CLI version collided with its own orphan and died on a non-fast-forward push, masking the real error. - `gh label create` was fatal under `bash -e` despite the `automated` label already existing on this repo. It is now non-fatal; `gh pr create --label` is the call that actually needs to succeed, and it still fails loudly. - One secret served two very different jobs. `smoke-skills.yml` and `smoke-rpa-skills.yml` are `pull_request`-triggered required checks on a public repo, so anyone who can push a branch here could read a credential that also carried repo write. Feed-read consumers now take `GH_PACKAGES_TOKEN`; `GH_PAT` is referenced only by the two `schedule`/`check_suite` workflows that need write. The `GH_PACKAGES_TOKEN || GH_PAT` fallback keeps every workflow green until the new secret exists — drop it once it does. Also corrects two comments claiming this PAT is shared with activation-gate.yml, which does not reference it. That claim sent the original Slack triage toward "expired PAT" when the token was valid and merely under-scoped. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(catalog): refuse to ship a catalog that lost a whole command group The 2026-07-30 21:39 UTC build dropped the entire `rpa debug` subtree (16 verbs) plus `rpa analyzer-rules list` and `rpa files diff`, and opened a PR that would have auto-merged. Cause was not a CLI change: `uip <group> --help` failed for those three groups, and collect_group marks a group unwalkable and returns no children when that happens. The group node itself survives, so the subtree disappears silently — 18 verbs is 1.3% of a 1384-verb catalog, well inside --max-drop-frac 0.2. The same three groups walked fine 16 hours earlier, and five *other* rpa groups failed in that earlier build instead, so the failures are transient rather than structural. Two changes: - collect_group retries a failed `--help` (3 attempts, linear backoff) before marking a group unwalkable. Only failing groups pay the cost. - New always-on guard: refuse to write when a group that was walked in the committed snapshot is unwalkable in this build. Verified against the two real snapshots — it reports exactly the 3 regressed groups / 18 lost verbs that --max-drop-frac passed. `--allow-unwalkable-regression` is the escape hatch for a genuine permanent loss, or for recovering when the committed snapshot is itself the flaky build. The guard stays quiet on the cases that are not regressions: leaf commands (no children in the previous snapshot), groups already unwalkable, groups genuinely deleted from the CLI (never enter the walk), and new groups. 10 unit tests cover those plus both retry paths. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs(ci): clarify why each workflow gets the read-only feed token Reviewer nits on #2398, both comment-only: - smoke-rpa-skills.yml: the token-split note ran into the `@dev` pinning paragraph mid-sentence. Split into its own paragraph and spell out the reason the `pull_request` trigger matters (a branch pusher on a public repo can read the secret), matching the wording in smoke-skills.yml. - run-coder-eval.yml: this workflow is `workflow_dispatch`-only, so the fork-PR argument does not apply to it. Say so, and name the actual reason for the narrower token here: least privilege. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>github.com-UiPath-skills · c45d31bf · 2026-07-31
- 0.2ETVfeat(discovery): add skills.sh.json, a zero-install trial path, and a drift guard (#2390) * feat(discovery): add skills.sh.json and a zero-install trial path We are already indexed on skills.sh (37 entries, 529 installs) and `npx skills add UiPath/skills` already works — but the page is an ungrouped flat list and the README never mentions either fact. - skills.sh.json groups all 24 skills using the README's existing four catalog sections. Display-only: it does not affect how the skills CLI installs anything. `notGrouped: bottom` pushes the 13 retired entries still indexed on our page (uipath-flow, uipath-rpa-workflows, uipath-case-management, ...) below the live sections — the only lever available without a support request to prune them. - README: skills.sh badge, plus an evaluation path via `npx skills use` that needs neither the UiPath CLI nor a project change. `uip skills install` stays the recommended path and the note says why (it auto-detects agents and auto-updates; npx does not). TODO before merge — confirm the grouping of seven skills that appear only in the README's generated status table, never in its descriptive catalog tables, so their placement here was inferred from the skill name alone: uipath-automation-discovery -> Solution & Planning uipath-connector-builder -> Authoring uipath-functions -> Authoring uipath-governance -> Platform & Operations uipath-insights -> Platform & Operations uipath-mcp-servers -> Platform & Operations uipath-tasks -> Platform & Operations The same taxonomy should then close the README catalog gap so there is one grouping rather than two. Not included (needs a request via skills.sh/contact): pruning the 13 retired entries, and asking whether install history can carry across the renames uipath-flow -> uipath-maestro-flow and uipath-case-management -> uipath-maestro-case (~40 installs of real signal). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat(ci): guard skills.sh.json against drift skills.sh.json is presentation-only — it never changes what the skills CLI installs — which is exactly why it rots unnoticed. A skill added, renamed, or removed under skills/ produces no error anywhere and the public page keeps showing the old grouping. This is the failure mode already visible on our live page: 13 renamed or retired skills still listed. scripts/check-skills-sh.py checks four things: 1. Parses — valid JSON, expected top-level shape. 2. Schema — the published skills.sh constraints, enforced locally so CI needs no network (groupings 1-50, title required and 1-120 chars, skills non-empty and <=500, description <=500, notGrouped in {top,bottom}, no unknown top-level keys, canonical $schema URL). 3. No duplicates — a skill appears in at most one grouping. 4. Bijection — every skills/<name>/ is grouped, every grouped name exists on disk. --fix is deliberately asymmetric: it removes grouped names that no longer exist (unambiguous) plus any grouping left empty, and refuses to place newly added skills, because which section a skill belongs to is an editorial call. It exits 1 while anything remains ungrouped so it can never be mistaken for "the manifest is now correct". When `groupings` is missing or malformed the coverage check is skipped, so the one finding that matters isn't buried under every skill on disk. Follows the scripts/check-skill-status.py pattern: findings-per-line text output, --json for tooling, and a paths-scoped workflow mirroring validate-skill-status.yml. The workflow uses no ${{ }} interpolation, triggers on pull_request rather than pull_request_target, and requests only contents:read. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs(contributing): document the skills.sh grouping step Without this, the first contributor to add a skill gets a red `Validate skills.sh.json against skills/` and no documentation saying why. Step 4 exists for exactly this reason for the status manifest; this mirrors it — what to add, which section, how to validate, and what CI enforces — plus the matching Quality Checklist line. Also states the thing that is easy to assume wrong: the grouping affects only the skills.sh page, never what `uip skills install` or the skills CLI installs. Renumbers the two optional steps that follow (5-6 -> 6-7). No internal anchors referenced them. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs: point skills.sh links at the canonical host `https://skills.sh/...` 308-redirects to `www.skills.sh`, and the page path 307s again to a lowercased owner — so the badge and page links each cost one or two hops. `https://www.skills.sh/uipath/skills` and `.../b/uipath/skills` both return 200 directly, with an identical badge. Left alone deliberately: the `$schema` value in skills.sh.json (and the matching constant in scripts/check-skills-sh.py) keeps the apex form `https://skills.sh/schemas/skills.sh.schema.json`. That is a service-defined identifier, spelled exactly as skills.sh documents it and as every other vendor repo shipping this file uses it — matching the spec matters more there than saving a redirect an editor follows anyway. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>github.com-UiPath-skills · 3e102178 · 2026-07-31
- 0.2ETVchore(preview): re-sync Maestro SDK skills to flow-builder-sdk@efd27ce (#2789) 🤖 Generated with Claude Code Co-Authored-By: [Claude](mailto:noreply@anthropic.com) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>github.com-UiPath-skills · cc03679e · 2026-08-25
- 0.1ETVchore(preview): re-sync Maestro SDK skills to flow-builder-sdk@3d5a94e (#2916) 🤖 Generated with Claude Code Co-Authored-By: [Claude](mailto:noreply@anthropic.com) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>github.com-UiPath-skills · 47ebbe24 · 2026-08-31
- 0.1ETVchore(preview): re-sync Maestro SDK skills to flow-builder-sdk@62c5a99 (#3238) 🤖 Generated with Claude Code Co-Authored-By: [Claude](mailto:noreply@anthropic.com) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>github.com-UiPath-skills · e7cefab3 · 2026-09-15
- 0.1ETVchore(preview): re-sync Maestro SDK skills to flow-builder-sdk@c0cf591 (#2754) 🤖 Generated with Claude Code Co-Authored-By: [Claude](mailto:noreply@anthropic.com) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>github.com-UiPath-skills · a7a1ac84 · 2026-08-22