From shopify-admin-skills
Audits Shopify staff accounts for stale logins, inactive status, and overpermissioned roles to surface security and access hygiene issues. Read-only GraphQL query.
npx claudepluginhub 40rty-ai/shopify-admin-skills --plugin shopify-admin-skillsThis skill uses the workspace's default tool permissions.
Audits all staff member accounts on the store to surface security and access-hygiene risks. Flags accounts that have not logged in for more than `stale_days` days, accounts that are inactive but still provisioned, and accounts with full / shop-owner-equivalent permissions. Read-only — no mutations. Provides the data foundation for a follow-up access review or deprovisioning workflow.
Implements RBAC for Shopify Plus apps via staff permissions, multi-location management, and organization features. Provides TypeScript code for GraphQL queries and role mapping.
Manages Saleor customers and staff including accounts, registration, addresses, permissions, and authentication via GraphQL mutations. Use for user management in Saleor apps.
Manages Shopify customers via GraphQL Admin API mutations/queries for create/update/delete/tags/metafields, Customer Account API, Multipass SSO, segmentation, B2B accounts.
Share bugs, ideas, or general feedback.
Audits all staff member accounts on the store to surface security and access-hygiene risks. Flags accounts that have not logged in for more than stale_days days, accounts that are inactive but still provisioned, and accounts with full / shop-owner-equivalent permissions. Read-only — no mutations. Provides the data foundation for a follow-up access review or deprovisioning workflow.
shopify store auth --store <domain> --scopes read_usersread_users| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| store | string | yes | — | Store domain (e.g., mystore.myshopify.com) |
| stale_days | integer | no | 90 | Flag accounts with no login activity in this many days |
| include_inactive | bool | no | true | Include accounts where active: false in the audit output |
| include_owner | bool | no | false | Include the shop owner row in flagged-account counts |
| format | string | no | human | Output format: human or json |
ℹ️ Read-only skill — no mutations are executed. Safe to run at any time. No staff accounts are deactivated or modified by this skill.
OPERATION: staffMembers — query
Inputs: first: 250, select id, name, email, active, isShopOwner, accountType, locale, lastSeen, pagination cursor
Expected output: All staff members with status and last-login data; paginate until hasNextPage: false
Compute days_since_last_seen per member. Flag any member with days_since_last_seen > stale_days as stale.
Flag any member with active: false (or accountType: SUSPENDED) as inactive but provisioned.
Flag any member with isShopOwner: true or accountType: COLLABORATOR with full permissions as high privilege for review.
Cross-tabulate: produce per-account record with all flags joined (stale, inactive, high_privilege).
# staffMembers:query — validated against api_version 2025-01
query StaffAccountAudit($after: String) {
staffMembers(first: 250, after: $after) {
edges {
node {
id
name
email
active
isShopOwner
accountType
locale
exists
phone
avatar {
url
}
privateData {
accountSettingsUrl
createdAt
}
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
Claude MUST emit the following output at each stage. This is mandatory.
On start, emit:
╔══════════════════════════════════════════════╗
║ SKILL: Staff Account Audit ║
║ Store: <store domain> ║
║ Started: <YYYY-MM-DD HH:MM UTC> ║
╚══════════════════════════════════════════════╝
After each step, emit:
[N/TOTAL] <QUERY|MUTATION> <OperationName>
→ Params: <brief summary of key inputs>
→ Result: <count or outcome>
On completion, emit:
For format: human (default):
══════════════════════════════════════════════
STAFF ACCOUNT AUDIT (stale threshold: <stale_days> days)
Total staff accounts: <n>
Active: <n>
Inactive (provisioned): <n>
Stale logins (>Nd): <n> (<pct>%)
High-privilege roles: <n>
Flagged accounts (top by risk):
"<name>" <email> last_seen: <Nd ago> flags: <stale,high_priv>
Output: staff_audit_<date>.csv
══════════════════════════════════════════════
For format: json, emit:
{
"skill": "staff-account-audit",
"store": "<domain>",
"stale_days_threshold": 90,
"total_accounts": 0,
"active_accounts": 0,
"inactive_accounts": 0,
"stale_accounts": 0,
"high_privilege_accounts": 0,
"output_file": "staff_audit_<date>.csv"
}
CSV file staff_audit_<YYYY-MM-DD>.csv with columns:
staff_id, name, email, account_type, is_shop_owner, active, last_seen, days_since_last_seen, is_stale, is_inactive, is_high_privilege, flags
| Error | Cause | Recovery |
|---|---|---|
THROTTLED | API rate limit exceeded | Wait 2 seconds, retry up to 3 times |
ACCESS_DENIED on staffMembers | Caller lacks read_users or staff-mgmt permission | Re-auth as Shop Owner / staff-admin |
lastSeen: null on a staff member | Account never logged in | Treat as days_since_last_seen = days_since_account_created; flag as stale |
| Empty staff list | Single-operator store (owner only) | Exit with 1 row (the owner); skill is still useful for record-keeping |
stale_days: 30 for high-risk stores (high-volume, large staff) and stale_days: 180 for very small teams where seasonal access is normal.days_since_last_seen descending to prioritize the longest-stale accounts first.staffMember-scoped audit log events before deprovisioning to ensure there is no in-flight work.