Best for
- Use when a task needs a dashboard click-path (Cloudflare token/Zero Trust, GitHub OAuth apps, any
terrylica/cc-skills/plugins/web-forge/skills/dashboard-forge/SKILL.md
Supervised browser automation of vendor dashboards for operations that have NO public API — minting scoped API tokens, creating OAuth apps, flipping account-level toggles. Drives a real Chrome over CDP with a persistent per-site profile (human logs in once, supervised; scripts do the rest), extracts secrets DOM-to-vault without ever exposing them, and survives UI drift via the step-and-shoot method. Use when a task needs a dashboard click-path (Cloudflare token/Zero Trust, GitHub OAuth apps, any
Decision brief
Some operations exist ONLY behind a vendor's web UI (GitHub fine-grained PATs and OAuth apps have no creation API; a Cloudflare token cannot grant itself new scopes). This skill is the canonical method for automating those click-paths safely: the human supervises and handles log…
Compatibility matrix
| Platform | Status | Evidence | What to check |
|---|---|---|---|
| Codex | Not declared | No explicit evidence | Portability before use |
| Claude Code | Not declared | No explicit evidence | Portability before use |
| Cursor | Not declared | No explicit evidence | Portability before use |
| Gemini CLI | Not declared | No explicit evidence | Portability before use |
Installation
The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.
npx skills add https://github.com/terrylica/cc-skills --skill "plugins/web-forge/skills/dashboard-forge"Inspect the Agent Skill "dashboard-forge" from https://github.com/terrylica/cc-skills/blob/05f53c5b24a445c1895e9b0590212e66cd70f39e/plugins/web-forge/skills/dashboard-forge/SKILL.md at commit 05f53c5b24a445c1895e9b0590212e66cd70f39e. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.
Workflow
Write the forge as small, resumable steps against a LONG-LIVED Chrome (launch once; each step connects, acts, disconnects — browser.close() on a CDP connection only detaches, Chrome keeps running). Never author one monolithic script against an unseen UI.
/459ecs/example-clinic/scripts/access-bootstrap/ — the 2026-07-23 run that canonicalized this skill: Cloudflare scoped-token forge + GitHub OAuth-app forge + idempotent Access bootstrap, end-to-end in one supervised session (decision record: that repo's compliance README §D10).
Browser-automate the MINIMUM: usually just (a) the login and (b) the one form that mints a scoped credential. Everything after that goes through the vendor's REAL API with the minted credential, written as an idempotent GET-before-POST bootstrap (see the cf-access-wall skill for…
A third mode, distinct from launching a per-site profile over CDP. Instead of owning a session, you borrow one that is already open in the operator's own Chrome and drive it via AppleScript:
Values ride PIPES: vault set --stdin (SCS vault). Never argv, never stdout,
Permission review
The documentation asks the agent to read local files, directories, or repositories.
**Read the JS from a FILE** (`set js to read POSIX file "/tmp/step.js" as «class utf8»`).The documentation includes network, browsing, or remote request actions.
`Error 400 (Bad Request)`. There is no URL that opens the create dialog; you must click throughEvidence record
| Signal | Value | Evidence type | Meaning |
|---|---|---|---|
| Quality score | 95/100 | Computed | Documentation, specificity, maintenance, and trust rules |
| Repository stars | 61 | Source | Repository attention, not individual Skill quality |
| Compatibility | 0 platforms | Source | Declared in the catalog source record |
| Usage guide | automated source guide | Editorial | Generated or reviewed according to the visible evidence level |
Pinned source
Some operations exist ONLY behind a vendor's web UI (GitHub fine-grained PATs and OAuth apps have no creation API; a Cloudflare token cannot grant itself new scopes). This skill is the canonical method for automating those click-paths safely: the human supervises and handles logins/2FA; the scripts do everything else, reproducibly.
Harness (SSoT): ../../lib/browser-forge.mjs — per-site
persistent Chrome profiles + CDP attach + login-wait + identity preflight + consent dismissal +
vault sinks. node ONLY (Bun's connectOverCDP times out). Requires playwright-core (pinned at
the repo root) and Chrome at the standard macOS path.
Self-Evolving Skill: dashboards drift constantly. When a selector misses or a flow changes, fix the forge script AND append the drift note to the Vendor Quirks section below — immediately, not later. Only update for real, reproducible breakage.
Write the forge as small, resumable steps against a LONG-LIVED Chrome (launch once; each step
connects, acts, disconnects — browser.close() on a CDP connection only detaches, Chrome keeps
running). Never author one monolithic script against an unseen UI.
launchChrome(site, loginUrl); the human signs in (incl. 2FA).
Detect completion with waitForLogin(ctx, probeUrl, ok) — poll an authenticated endpoint via
ctx.request with the context cookies. NEVER navigate a visible tab to poll: you would reload
a half-typed login form.assertIdentity(actual, expected, resource). An
account-owned resource created under the wrong login is a silent disaster (it happened:
an OAuth app landed under the wrong GitHub user mid-forge because the human switched accounts).shot(page, name)
after each. When a locator misses, READ the latest shot, adapt, re-run just that step. Prefer
role/label-based locators (getByRole, description-text anchoring) over CSS classes; for
checkbox grids, page.evaluate walking from a UNIQUE description text up to its row is far
more drift-proof than nth-child chains.dismissConsent(page) when a click times out
mysteriously, then retry. GitHub-style sudo/2FA walls mid-flow: pause and let the supervising
human clear them (or see gh-fine-grained-pat's autosudo.mjs for the autonomous passkey path).page.evaluate → match the value
→ vaultSet(scope, path, value). NEVER screenshot a reveal page — an agent reading that
screenshot puts the secret into the conversation context permanently. If a reveal was
accidentally captured, purge the file AND treat the secret as context-exposed (rotate if the
transcript leaves the machine).purgeShots() (breadcrumbs can show near-secret state), then
teardown(site) — kills the SPECIFIC pid on the CDP port, never pkill -f (process-storm
policy, ~/.claude/CLAUDE.md).Browser-automate the MINIMUM: usually just (a) the login and (b) the one form that mints a scoped credential. Everything after that goes through the vendor's REAL API with the minted credential, written as an idempotent GET-before-POST bootstrap (see the cf-access-wall skill for the worked template). UI automation is the crowbar, not the workflow.
A third mode, distinct from launching a per-site profile over CDP. Instead of owning a session, you borrow one that is already open in the operator's own Chrome and drive it via AppleScript:
tell application "Google Chrome"
execute (tab N of window M) javascript "…"
end tell
Requires View → Developer → Allow JavaScript from Apple Events (persisted per profile as
browser.allow_javascript_apple_events in Preferences — grep it to check before promising
anything). You then have full DOM read/write with no driver, no profile copy, and no port.
When it is the RIGHT tool: the console is behind a passkey / hardware-key / step-up flow that you must not automate, and a human session already exists. You never touch the credential — you type inside a door somebody else opened. That distinction is the whole justification, and it is worth stating out loud in whatever you write afterwards.
When it is the WRONG tool: anything unattended, anything needing isolation, anything that should not be able to see the operator's other tabs. It has no sandbox by construction.
Hard-won rules, each one paid for:
activate and set index REORDER windows, so an
index captured a moment ago can point somewhere else by the time you use it. Re-resolve on
every call. Make the URL needle specific — "admin.google.com" will happily match a different
admin tab and you will read the wrong page and believe it.set js to read POSIX file "/tmp/step.js" as «class utf8»).
Interpolating JS through bash → osascript → AppleScript string literals mangles quotes and
backslashes in ways that fail silently or, worse, alter the script.offsetParent is null for position: fixed, which is how essentially every Material/modal
dialog is rendered. A "is it visible" filter built on offsetParent !== null therefore hides
the dialog you are looking for and you conclude the form never opened. Use
getBoundingClientRect() width/height instead.el.value updates the DOM but leaves
Angular/React/Closure's model stale, so the form submits empty. Use
Object.getOwnPropertyDescriptor(HTMLInputElement.prototype,'value').set.call(el, v) then
dispatch input + change (+ blur). Read the value back and assert it.document.elementFromPoint(x,y) and compare to the intended element. In an admin console a
mis-aimed click is not a failed test, it is an unintended action.open -a. make new window via Apple
Events still works. Never quit or restart the operator's browser to "fix" it; you will destroy
their tabs.vault set --stdin <scope> <path> (SCS vault). Never argv, never stdout,
never a chat transcript.✓ vaulted (len 53)).~/.local/share/web-forge/profile-<site>) hold live sessions — sensitive, never
committed, listed in backups as credential-equivalent.Cloudflare 2026-07 token UI: the old template-picker → 3-combobox flow is GONE. "Create
Token" lands directly on a categorized checkbox form ("Cloudflare One / Zero Trust" section →
per-group Read/Revoke/Edit boxes); submit is "Review token" → "Create token" → modal reveal.
Tokens are cfat_… (53 chars), not the old 40-char format.
Cloudflare account-owned tokens (2026-07-23): /user/tokens/verify ALWAYS rejects them
("Invalid API Token"); verify with /accounts/{id}/tokens/verify. Don't misdiagnose a working
token as dead.
Cloudflare dashboard consent (2026-07-23): OneTrust overlay appears minutes into a session and intercepts pointer events page-wide.
GitHub OAuth apps (2026-07-23): no creation API (same as fine-grained PATs). Form fields:
oauth_application[name|url|callback_url]. "Generate a new client secret" triggers sudo mode;
a FRESH login usually has a sudo grace window — create the app right after login and the secret
generation is prompt-free. Client secrets render as a 40-hex blob.
Azure Portal — ambiguous accessible names (2026-08-02): every blade's close button is labelled
"Close content '<Blade Title>'", so on "Register an application" a fuzzy
getByRole("button", {name:/register/i}).first() matches the CLOSE button, not the submit. It
clicks, Playwright reports success, the blade shuts and nothing is created. Cost two runs, and the
second created a DUPLICATE once the truth surfaced. Use clickExact() — it refuses on a non-exact
name and prints the candidate list (verified live: ["Close content 'Register an application'","Register"]).
Azure Portal — two elements match input[placeholder*="Search"] (2026-08-02): the page-wide
search in the masthead matches BEFORE any blade's own filter. Typing the role name into it left the
role grid unfiltered, so an exact row lookup found 0 rows and the wizard advanced with no role
selected. Anchor on the distinctive placeholder ("Search by role name, description, permission, or ID").
Azure Portal — a list view can lie about creation (2026-08-02): after successfully creating an
app registration as a GUEST (#EXT#) user, App registrations → Owned applications said "This
account isn't listed as an owner of any applications in this directory." True (a guest creator is not
auto-assigned owner) and deeply misleading. Ground truth is the notifications pane ("Successfully
created application X") or the All applications tab. Never confirm a mutation from the same
console's default list view.
Azure Portal — tokens are in memory, not localStorage (2026-08-02): an MSAL SPA of this
generation keeps ARM/Graph access tokens in memory; a localStorage sweep returns nothing. Capture
them off the wire with captureBearer(page, "management.azure.com" | "graph.microsoft.com"). With an
ARM token the whole 3-tab role-assignment wizard collapses into one idempotent PUT (HTTP 201 first
try) — the clearest instance of the Hybrid rule in this log.
Azure Portal — a cached blade issues no request (2026-08-02): navigating to a view the SPA has
already hydrated produces zero traffic, so token capture silently yields null, which reads exactly
like "no permission". captureBearer retries with a reload() for this reason. The
App-registrations LIST blade reliably re-queries Graph; the Entra Overview blade often does not.
Azure — the Portal and the CLI are DIFFERENT Entra apps (2026-08-02): portal
c44b4083-3bb0-49c1-b47d-974e53cbdf3c, CLI 04b07795-8ddb-461a-bbee-02f9e1bf7b46. A Conditional
Access policy scoped to the CLI (AADSTS530035, "Device state: Unregistered") therefore does not
block the portal. This asymmetry is what makes a browser forge the only way in — and note that
az account list then returns [], which is a consequence of the block and not evidence that no
subscription exists.
Tailscale — console moved and OAuth clients were renamed (2026-08-05): login.tailscale.com
redirects to console.tailscale.com, and /admin/settings/oauth redirects to
/admin/settings/trust-credentials ("OAuth clients" is now "Trust credentials", created via a
button labelled just Credential). Auth keys stayed at /admin/settings/keys.
Tailscale — Radix checkboxes: the <input> is a decoy (2026-08-05): every scope checkbox
renders a real <input type=checkbox> that is aria-hidden, opacity:0, pointer-events:none,
next to a <button role="checkbox" data-state="checked|unchecked"> that holds the actual state.
Clicking the input — even with {force:true} — reports success and changes NOTHING; it cost a run
that looked like it selected six scopes and submitted an empty form. Click
button[role=checkbox][id="<scope>"] and assert via data-state. Bonus: the button ids ARE the
API scope names (auth_keys = write, auth_keys:read = read, devices:core, policy_file),
which is the most drift-proof selector on the page — better than the row-title walk.
Tailscale — a 50-char cap silently disables the wizard (2026-08-05): the OAuth/credential
description is labelled "(optional)" but capped at 50 characters, and exceeding it leaves
Continue disabled with no inline error near the button. Symptom is a permanently disabled
submit; the rule is only visible in body text ("Descriptions can be a maximum of 50 characters").
When a submit stays disabled, dump the form's body text before suspecting the click.
Tailscale — write scopes are gated on tags, so OAuth clients need an ACL change first
(2026-08-05): selecting ANY write scope surfaces "Tags (required for write scope)", and tags only
exist if the tailnet policy file declares them. So an OAuth client (the durable, non-expiring
credential) cannot be minted in one pass on a tailnet with no tags — it needs a policy-file edit,
which is a security change the operator should approve. A plain user-owned auth key from
/admin/settings/keys has no tag requirement and is the right unblock when the goal is just
joining one device.
Seeding a forge profile from the operator's real Chrome (2026-08-05): when the per-site profile
has no session and an interactive login would be the only manual step, copy Local State +
Default/Cookies (+ Default/Network/Cookies if present) from
~/Library/Application Support/Google/Chrome into a throwaway dir and point
WEB_FORGE_PROFILE_DIR at it. Cookies decrypt because the macOS Keychain key is per-user, not
per-profile, and no Keychain prompt appears (same Chrome binary). The operator's running Chrome is
untouched — different --user-data-dir. Delete the seeded dir afterwards: it holds a copy of
live session cookies and is credential-equivalent.
shot() used to report phantom screenshots (fixed 2026-08-07): it wrapped page.screenshot
in .catch(() => {}) and returned the intended path regardless, so a failed capture printed a
confident [shot] …png for a file that never existed (caught live — a 30 s font-loading timeout
on the Lark console, path printed with existsSync === false). Screenshots are the only evidence
a forge has when a selector misses, so a phantom one makes "capture failed" indistinguishable
from "the page was blank". It now returns null and says FAILED on both the throw path and the
resolved-but-no-file path. Callers must treat null as "no evidence", never as a path.
Lark/Feishu developer console — the scope table is VIRTUALIZED (2026-08-05): document .querySelectorAll("tr") returns 1 and [role="row"] returns 0; rows are
div.virtual-table__row and only ~25 exist in the DOM at once, so scroll-and-scrape silently
under-reports. Never enumerate it by scrolling — type into the scope filter instead, anchored on
its distinctive placeholder input[placeholder^="E.g."] (the masthead "Search documentation" box
matches a generic input[placeholder*="Search"] FIRST — the same trap as the Azure entry above).
Lark console — "More" in Security Settings is a section anchor, not a button (2026-08-07):
getByText("More", {exact:true}) matches exactly one node, and clicking it times out at 10 s with
no visible cause. Scroll and read the whole page instead of clicking.
Feishu docs are JS-gated but expose a markdown twin (2026-08-07): fetching a doc page yields
only its title, but the HTML advertises <link rel="alternate" type="text/markdown"> — append
.md to the doc URL and curl returns the full text, Chinese included. The Chinese pages carry
detail the English ones omit (the app-level "refresh user_access_token" switch appears only
there). Wrong slugs answer This document is not found, so probe a few rather than assuming one.
Chrome silently ignores --remote-debugging-port on the DEFAULT data directory
(2026-08-12): Chrome starts normally, the flag appears in ps, and the port never binds. The
only signal is one line on stderr — DevTools remote debugging requires a non-default data directory. Specify this using --user-data-dir. — which is invisible if stderr goes to a log
nobody reads. curl 127.0.0.1:<port>/json/version then fails with "connection refused" and
looks like a dead browser rather than a rejected flag. Diagnose with
lsof -nP -iTCP -sTCP:LISTEN -a -p <pid>: a Chrome that is up but listening on nothing is
this, every time. Always pass an explicit --user-data-dir alongside the debugging port —
which the harness already does, and which is exactly why the harness works and ad-hoc
invocations do not.
Google Admin console — the group list lies after a write (2026-08-12): immediately after
creating a group, Directory → Groups still rendered the empty state, "Your organization
doesn't have any groups yet", for long enough to read as a failure. The group existed the
whole time. This is the SECOND vendor to do this — see the Azure "a list view can lie about
creation" entry above — so treat it as a rule rather than a quirk: never confirm a mutation
from the same console's default list view. Confirm from a DIFFERENT system. Here the proof was
that GCP's setIamPolicy rejects members that do not exist and accepted the new group, so
the IAM grant doubled as the existence check.
Google Admin console — repeated clicks STACK duplicate dialogs (2026-08-12): clicking
"Create group" twice (e.g. once via .click(), once via a synthetic pointer sequence when the
first appeared to do nothing) leaves TWO form instances in the DOM. A later "fill the field with
this aria-label" then hits an arbitrary one and the visible form stays empty. Reload to a clean
state before filling, and assert the field count is exactly 1 first.
Google Admin console — controls are Closure div[role=button] with obfuscated classes
(2026-08-12): e.g. class="U26fgb O0WRkf oG5Srb …". Never build a CSS-path selector; match on
visible text or aria-label. Plain .click() DOES work on them — if a click appears to do
nothing, suspect that you are reading the wrong tab before you conclude the click failed.
Google Admin console — a preset flips to "Custom" when you narrow a sub-setting
(2026-08-12): choosing the Restricted access-type preset and then setting "Who can join" to
Only invited users relabels Access type as Custom. That is correct and expected, not a
failed selection. Assert on the SUB-SETTINGS you care about, never on the preset label.
Google Admin console — /ac/groups/new is not a deep link (2026-08-12): it answers
Error 400 (Bad Request). There is no URL that opens the create dialog; you must click through
from /ac/groups.
Seeding a forge profile with copied cookies NO LONGER WORKS FOR GOOGLE (2026-08-13): the
"Seeding a forge profile from the operator's real Chrome" recipe above is now dead for
accounts.google.com. 109 google.com cookies copied cleanly out of the operator's profile and
the very first navigation still landed on the sign-in page — Google binds sessions to the profile's
device key (DBSC), so a cookie copy authenticates nothing. The recipe remains valid for vendors that
do plain cookie sessions; budget a supervised login for Google and do not plan a run around
borrowing its session. Symptom to recognize: a clean copy, a plausible cookie count, and an
immediate redirect to sign-in — which reads as "I copied the wrong profile" and is not.
Google's sign-in identifier input is type="text", not type="email" (2026-08-13): the field is
#identifierId. A guarded input[type="email"] fill therefore matches ZERO nodes and, if the fill
is wrapped in if (await field.count()), does nothing at all — the screenshot then shows an empty
box, which reads as "the form rejected my value" rather than "my selector missed". Anchor on
#identifierId. (Same family as the Azure/Lark placeholder traps: a selector that matches nothing is
far more expensive to diagnose than one that matches the wrong thing, because the failure is silent.)
Chrome ignores --profile-directory when another Chrome owns a DIFFERENT --user-data-dir
(2026-08-13): with a leftover forge Chrome running, open -a "Google Chrome" --args --profile-directory="Profile 22" <url> and the direct-binary equivalent both print "Opening in
existing browser session" and open nothing — no window, no error, exit 0. AppleScript then
enumerates the FORGE's tabs, so tell application "Google Chrome" silently drives the wrong browser.
Check ps -axo pid,command | grep "[G]oogle Chrome" | grep -v " --type=" for a stray
--user-data-dir before trusting borrowed-session mode, and note two Chrome PIDs can coexist
where only one receives Apple Events. Prefer an explicit CDP profile over fighting for the default.
Masking a value you have not validated hides the ERROR, not the secret (2026-08-13): piping a
token-minting command through 2>&1 | sed 's/./x/g' to keep a secret out of the transcript printed a
confident row of xs for what was actually ERROR: Reauthentication failed…. The masking made a
failure indistinguishable from success, and the next call's 401 was the only clue. Mask lengths and
exit codes (len=${#TOK} rc=$?), never a raw stream you have not first checked is a value —
${#TOK} would have read 0 and ended it immediately.
Apple Events execute javascript needs SYNCHRONOUS JS — a Promise serializes to nothing
(2026-08-19): the idiomatic (async () => { … })() probe returns a Promise, which crosses the
Apple Event boundary as an empty string. The step reads as "the page returned no data", i.e.
exactly like a failed selector, and the natural response is to rewrite selectors that were fine.
Write borrowed-session steps as a plain synchronous IIFE returning JSON.stringify(out); where a
step genuinely needs to wait, split it into two invocations with the sleep in the shell, not
in the page.
GitHub's React issues UI exposes NO file input and NO React onDrop (2026-08-19): attaching a
file to an issue comment used to mean driving file-attachment + input[type=file]. On the current
UI a DOM sweep finds zero input[type=file], zero <file-attachment>, and zero
__reactProps$*.onDrop anywhere in the textarea's ancestor chain — the only evidence an upload path
exists is the hint text "Paste, drop, or click to add files". Do not conclude uploading is
impossible: dispatching a synthetic DragEvent sequence (dragenter, dragover, drop) carrying a
DataTransfer with one File at the textarea works. Confirm it by checking dispatchEvent
returned false on the drop (i.e. preventDefault was called — the listener exists even though no
property exposes it), then poll the textarea for the injected
[name](https://github.com/user-attachments/files/…) markdown. Two follow-ons worth knowing: the
upload is not a page mutation, so GitHub's own CSP blocks an in-page authenticated fetch to
verify it; and navigating to the resulting URL downloads rather than renders, so the tab
self-closes — which reads as "the tab vanished, something broke" when it is the success path.
Verify from outside the browser instead (shasum the downloaded file against the original;
Chrome's History DB downloads table records total_bytes and state).
Payload SIZE is rarely the Apple Events failure — quoting is (2026-08-19): a 106 KB step script
(78 KB file base64-encoded) round-trips through osascript intact; a measured probe put a
104,576-char string through unharmed. The actual break was an unterminated JS string literal,
caused by emitting var B64 = " and then a newline before the payload. Keep any large literal on
one physical line, and when a big step fails, test the transport with a synthetic string of the
same length before blaming a limit that does not exist.
1Password web — a persistent profile keeps the Secret Key, so the wall is PASSWORD-ONLY
(2026-08-24): eonlabs.1password.com redirected to /signin with the account already resolved —
email prefilled ([email protected]), one input#master-password, no Secret Key field. So
"the profile still has cookies" does not mean the session is live (the profile's Cookies DB
was 5.9 MB and 3 days old), and the resulting wall is weaker than the "Secret Key + master
password" a cold login demands — which matters because a forge told to "STOP if it demands a full
sign-in" can misread a password-only wall as something it may proceed through. It may not: the
master password is exactly the credential a forge must never type or fetch. Detect it on
input#master-password and hand the parked Chrome back to the human for the supervised login.
Corollary for the same vendor: the op CLI is not a fallback — with desktop-app integration
(system_auth_latest_signin in ~/.config/op/config) every authenticated call raises a Touch ID
prompt and dies with [ERROR] authorization timeout after 60 s if nobody is at the machine, while
op account list still answers from local config and makes it look configured. Both doors need
the same absent human, so there is no clever route around it.
The PAT skill (gh-tools) is the origin of this harness and keeps its own battle-tested copy +
GitHub-specific machinery (autosudo/webauthn/multi-account). NEW forges build on web-forge's
lib/browser-forge.mjs; the PAT skill migrates here only in a deliberate, tested pass — never
casually (anti-fragility: don't destabilize a working credential forge for DRY points).
~/459ecs/example-clinic/scripts/access-bootstrap/ — the 2026-07-23 run that canonicalized this
skill: Cloudflare scoped-token forge + GitHub OAuth-app forge + idempotent Access bootstrap,
end-to-end in one supervised session (decision record: that repo's compliance README §D10).
After this skill completes, check before closing:
Frequently asked questions
Some operations exist ONLY behind a vendor's web UI (GitHub fine-grained PATs and OAuth apps have no creation API; a Cloudflare token cannot grant itself new scopes). This skill is the canonical method for automating those click-paths safely: the human supervises and handles log…
The source record exposes this install command: npx skills add https://github.com/terrylica/cc-skills --skill "plugins/web-forge/skills/dashboard-forge". Inspect the command and pinned source before running it.
Static rules flagged read-files, network in the source; the page lists the matching lines and excerpts.
Alternatives
oaustegard/claude-skills
Generate hierarchical _FEATURES.md files that describe what a codebase DOES from a user/consumer perspective, anchored to source symbols via tree-sitting. Supports large complex codebases through feature-driven decomposition into sub-feature files. Uses a multi-pass synthesis: orientation → detail → overview rewrite. Use when someone says "what does this do", "document features", "feature inventory", "_FEATURES.md", or needs to understand a codebase's purpose before modifying it. Complements tre
HKUDS/Vibe-Trading
Create, modify, and optimize quantitative trading strategies, then backtest and evaluate them.
vasilyu1983/AI-Agents-public
Guides iOS testing with XCTest, XCUITest, Swift Testing, simctl, and xcresult. Use when choosing destinations, controlling flakes, or parsing test artifacts for native apps.
brucesongs/kali-claw
Insecure Design (OWASP A06:2025) focuses on security flaws in system architecture and design phases, rather than code implementation-level bugs.