{"id":"05790383-0a39-4e32-af00-cd87736f5b73","entityType":"agent","slug":"clawhub-zw008-identity-aiops","name":"identity-aiops","canonicalUrl":"https://www.xpersona.co/agent/clawhub-zw008-identity-aiops","canonicalPath":"/agent/clawhub-zw008-identity-aiops","generatedAt":"2026-10-10T17:36:43.196Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-10T14:17:47.744Z","emptyReason":null},"description":"Use this skill whenever the user needs to operate a Keycloak or authentik identity provider — a one-shot overview, realm settings, users with sessions/credentials/groups/lockout status, authentication and admin events, OAuth/OIDC clients, four flagship RCAs (login-failure/lockout-storm, stale access, client misconfiguration, MFA coverage), and governed writes (disable/enable a user, revoke sessions, require a password reset, replace redirect URIs, rotate a client secret). Always use this skill for \"Keycloak\", \"authentik\", \"realm\", \"SSO users\", \"login failures\", \"brute force logins\", \"locked out users\", \"stale accounts\", \"service account misuse\", \"redirect URI\", \"PKCE\", \"implicit flow\", \"client secret rotation\", \"MFA coverage\", \"who has no 2FA\" when the context is a Keycloak/authentik IdP. Do NOT use when the target is something other than a Keycloak/authentik identity provider (a hypervisor, storage appliance, backup product, container-orchestration cluster, firewall, database, or OT/industrial equipment) — route those to the appropriate other AIops-tools skill. Cloud IdPs (Okta, Entra ID, Auth0) are out of scope. Governed identity operations with a built-in governance harness (audit, policy, token budget, undo, risk-tiers).","descriptionLabel":"Source description","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 1.4K downloads reported by the source. Last updated 10/10/2026.","installCommand":"clawhub skill install s171xgnmqse0nqvgqvqnaq5f9183kyre:identity-aiops","sourceUrl":"https://clawhub.ai/zw008/identity-aiops","homepage":"https://clawhub.ai/zw008/skills/identity-aiops","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/zw008/identity-aiops","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/zw008/skills/identity-aiops","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":63,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"identity-aiops technical dossier on Xpersona with agent coverage, OPENCLEW support, and live trust metadata."},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-10T14:17:47.744Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-10T14:17:47.744Z","emptyReason":null},"stars":null,"forks":null,"downloads":1391,"packageName":null,"latestVersion":"0.8.5","tractionLabel":"1.4K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-10T14:17:47.744Z","emptyReason":null},"lastUpdatedAt":"2026-10-10T14:17:47.744Z","lastCrawledAt":"2026-10-10T14:17:47.744Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-11T14:17:47.744Z","lastVerifiedAt":null,"highlights":[{"version":"0.8.5","createdAt":"2026-09-16T23:25:43.154Z","changelog":"- Updated documentation for agent guardrails in references/agent-guardrails.md. - Removed obsolete skill-card.md file. - General documentation updates and cleanup.","fileCount":7,"zipByteSize":20254},{"version":"0.8.4","createdAt":"2026-09-16T05:15:05.770Z","changelog":"- Removed the file skill-card.md. - No user-facing functionality or behavior was changed in this release.","fileCount":7,"zipByteSize":19665},{"version":"0.8.3","createdAt":"2026-09-15T05:59:39.806Z","changelog":"- Removed the file: skill-card.md - No changes to functionality or interface - No impact on user experience or skill usage","fileCount":7,"zipByteSize":19822},{"version":"0.8.2","createdAt":"2026-09-12T14:23:32.351Z","changelog":"- skill-card.md file removed. - Minor edits to SKILL.md: updated the OpenClaw plugin install instructions (`clawhub:@aiops-tools/identity-aiops` → `clawhub:@zw008/identity-aiops`) and the example output (\"Visibl\" → \"Visible to m\"). - No changes to core features, functionality, or tool list.","fileCount":7,"zipByteSize":19800},{"version":"0.8.1","createdAt":"2026-09-12T10:07:21.104Z","changelog":"## identity-aiops 0.8.1 - Documentation updated in SKILL.md for clarity and additional usage guidance. - Installation and usage instructions improved; now includes OpenClaw integration details. - Removed redundant skill-card.md file for better maintainability. - No functional or toolset changes to the skill itself.","fileCount":7,"zipByteSize":19723},{"version":"0.8.0","createdAt":"2026-09-12T00:55:54.201Z","changelog":"identity-aiops 0.8.0 - Changed metadata requirements: now accepts either identity-aiops or uvx as valid binaries. - Updated environment variable recommendations to make IDENTITY_AIOPS_CONFIG and IDENTITY_AIOPS_MASTER_PASSWORD optional. - Small compatibility clarifications in metadata; overall functionality unchanged. - Removed obsolete file: skill-card.md.","fileCount":7,"zipByteSize":19640},{"version":"0.7.0","createdAt":"2026-08-10T06:51:04.370Z","changelog":"- skill-card.md file removed, eliminating the per-release skill summary card. - No functional or user interface changes; this update contains only documentation cleanup.","fileCount":7,"zipByteSize":19647},{"version":"0.6.0","createdAt":"2026-08-03T05:52:52.850Z","changelog":"- Removed the file skill-card.md from the project. - No changes to core functionality or interfaces.","fileCount":7,"zipByteSize":19708}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s171xgnmqse0nqvgqvqnaq5f9183kyre:identity-aiops","setupComplexity":"low","setupSteps":["Install using `clawhub skill install s171xgnmqse0nqvgqvqnaq5f9183kyre:identity-aiops` in an isolated environment before connecting it to live workloads.","No published capability contract is available yet, so validate auth and request/response behavior manually.","Review the upstream CLAWHUB listing at https://clawhub.ai/zw008/identity-aiops before using production credentials."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-zw008-identity-aiops/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-zw008-identity-aiops/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-zw008-identity-aiops/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-zw008-identity-aiops/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-zw008-identity-aiops/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-zw008-identity-aiops/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-10T17:36:43.193Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-zw008-identity-aiops/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-zw008-identity-aiops/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-zw008-identity-aiops/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-zw008-identity-aiops/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-10T14:17:47.744Z","emptyReason":null},"readme":"Skill: identity-aiops\n\nOwner: zw008\n\nSummary: Use this skill whenever the user needs to operate a Keycloak or authentik identity provider — a one-shot overview, realm settings, users with sessions/credentials/groups/lockout status, authentication and admin events, OAuth/OIDC clients, four flagship RCAs (login-failure/lockout-storm, stale access, client misconfiguration, MFA coverage), and governed writes (disable/enable a user, revoke sessions, require a password reset, replace redirect URIs, rotate a client secret). Always use this skill for \"Keycloak\", \"authentik\", \"realm\", \"SSO users\", \"login failures\", \"brute force logins\", \"locked out users\", \"stale accounts\", \"service account misuse\", \"redirect URI\", \"PKCE\", \"implicit flow\", \"client secret rotation\", \"MFA coverage\", \"who has no 2FA\" when the context is a Keycloak/authentik IdP. Do NOT use when the target is something other than a Keycloak/authentik identity provider (a hypervisor, storage appliance, backup product, container-orchestration cluster, firewall, database, or OT/industrial equipment) — route those to the appropriate other AIops-tools skill. Cloud IdPs (Okta, Entra ID, Auth0) are out of scope. Governed identity operations with a built-in governance harness (audit, policy, token budget, undo, risk-tiers).\n\nTags: latest:0.8.5\n\nVersion history:\n\nv0.8.5 | 2026-09-16T23:25:43.154Z | auto\n\n- Updated documentation for agent guardrails in references/agent-guardrails.md.\n- Removed obsolete skill-card.md file.\n- General documentation updates and cleanup.\n\nv0.8.4 | 2026-09-16T05:15:05.770Z | auto\n\n- Removed the file skill-card.md.\n- No user-facing functionality or behavior was changed in this release.\n\nv0.8.3 | 2026-09-15T05:59:39.806Z | auto\n\n- Removed the file: skill-card.md\n- No changes to functionality or interface\n- No impact on user experience or skill usage\n\nv0.8.2 | 2026-09-12T14:23:32.351Z | auto\n\n- skill-card.md file removed.\n- Minor edits to SKILL.md: updated the OpenClaw plugin install instructions (`clawhub:@aiops-tools/identity-aiops` → `clawhub:@zw008/identity-aiops`) and the example output (\"Visibl\" → \"Visible to m\").\n- No changes to core features, functionality, or tool list.\n\nv0.8.1 | 2026-09-12T10:07:21.104Z | auto\n\n## identity-aiops 0.8.1\n\n- Documentation updated in SKILL.md for clarity and additional usage guidance.\n- Installation and usage instructions improved; now includes OpenClaw integration details.\n- Removed redundant skill-card.md file for better maintainability.\n- No functional or toolset changes to the skill itself.\n\nv0.8.0 | 2026-09-12T00:55:54.201Z | auto\n\nidentity-aiops 0.8.0\n\n- Changed metadata requirements: now accepts either identity-aiops or uvx as valid binaries.\n- Updated environment variable recommendations to make IDENTITY_AIOPS_CONFIG and IDENTITY_AIOPS_MASTER_PASSWORD optional.\n- Small compatibility clarifications in metadata; overall functionality unchanged.\n- Removed obsolete file: skill-card.md.\n\nv0.7.0 | 2026-08-10T06:51:04.370Z | auto\n\n- skill-card.md file removed, eliminating the per-release skill summary card.\n- No functional or user interface changes; this update contains only documentation cleanup.\n\nv0.6.0 | 2026-08-03T05:52:52.850Z | auto\n\n- Removed the file skill-card.md from the project.\n- No changes to core functionality or interfaces.\n\nv0.5.0 | 2026-08-02T09:39:22.546Z | auto\n\n- Removed the file skill-card.md from the project.\n- No changes to features, compatibility, description, or functionality.\n- Documentation and user-experience remain unchanged for this version.\n\nv0.4.0 | 2026-07-21T09:41:07.485Z | auto\n\nidentity-aiops 0.4.0\n\n- Tightened and clarified governance and risk-tiers documentation.\n- Updated wording in SKILL.md and references to better match auditing and permission practices.\n- Clarified that permitted write actions are based on agent judgment or connected account rights; the tool records, but does not enforce.\n- Removed unused file: skill-card.md. \n- Improved descriptions in reference and setup documentation.\n\nv0.3.0 | 2026-07-20T11:15:20.564Z | auto\n\n- Removed the file: skill-card.md\n- No changes to functionality or user experience.\n- The skill continues to provide governed identity operations for Keycloak and authentik, with 29 tools and built-in governance features.\n\nv0.2.2 | 2026-07-20T04:08:47.561Z | auto\n\n- Removed the file skill-card.md.\n- No user-facing features or tooling were changed.\n\nv0.2.1 | 2026-07-20T03:09:37.896Z | auto\n\n- Removed the file: skill-card.md\n- No user-facing features or tool changes; documentation file cleanup only.\n\nv0.2.0 | 2026-07-19T03:51:25.519Z | auto\n\nidentity-aiops 0.2.0\n\n- Expanded toolset from 27 to 29 operations, adding undo capabilities (undo_list, undo_apply).\n- Documentation overhaul: reworked SKILL.md for clarity, concise summary, usage tags, and improved structure.\n- Added agent guardrails reference and updated setup/capabilities docs.\n- Removed deprecated skill-card.md for better maintainability.\n- Upgraded verification status section: clearly states mock-validation, testability in a lab, and directs to verification checklist.\n\nv0.1.1 | 2026-07-17T06:05:35.507Z | auto\n\nidentity-aiops 0.1.1\n\n- Version incremented to 0.1.1 with no file changes.\n- No updates or modifications detected in source files or documentation.\n- Functionality and features remain unchanged from the previous release.\n\nv0.1.0 | 2026-07-17T05:58:06.179Z | auto\n\nidentity-aiops 0.1.0 (Initial Release)\n\n- Preview release offering governed, mock-validated identity operations for Keycloak and authentik.\n- Provides a unified toolset for user, group, event, client, and audit analysis—27 tools in total.\n- Includes four flagship root-cause analyses (login-failure/lockout storm, stale access, client misconfiguration, MFA coverage).\n- Risk-tiered and auditable write operations (disable/enable user, revoke sessions, password reset, client secret rotation, redirect URI changes) with undo and approval gates.\n- Credentials are encrypted on disk with Fernet/scrypt; no plaintext storage or logging.\n- All actions are audited locally; no live IdP connection—preview/mock only.\n\nArchive index:\n\nArchive v0.8.5: 7 files, 20254 bytes\n\nFiles: references/agent-guardrails.md (11335b), references/capabilities.md (5977b), references/cli-reference.md (2965b), references/setup-guide.md (3798b), skill-card.md (2935b), SKILL.md (17904b), _meta.json (133b)\n\nFile v0.8.5:SKILL.md\n\n---\nname: identity-aiops\nslug: identity-aiops\ndisplayName: \"Identity AIops\"\nsummary: \"Governed Keycloak + authentik identity ops: users, events, clients, MFA, RCA. 29 tools.\"\nlicense: MIT\nhomepage: https://github.com/AIops-tools/Identity-AIops\ntags: [aiops, mcp, governance, identity]\ndescription: >\n  Use this skill whenever the user needs to operate a Keycloak or authentik identity provider — a one-shot overview, realm settings, users with sessions/credentials/groups/lockout status, authentication and admin events, OAuth/OIDC clients, four flagship RCAs (login-failure/lockout-storm, stale access, client misconfiguration, MFA coverage), and governed writes (disable/enable a user, revoke sessions, require a password reset, replace redirect URIs, rotate a client secret).\n  Always use this skill for \"Keycloak\", \"authentik\", \"realm\", \"SSO users\", \"login failures\", \"brute force logins\", \"locked out users\", \"stale accounts\", \"service account misuse\", \"redirect URI\", \"PKCE\", \"implicit flow\", \"client secret rotation\", \"MFA coverage\", \"who has no 2FA\" when the context is a Keycloak/authentik IdP.\n  Do NOT use when the target is something other than a Keycloak/authentik identity provider (a hypervisor, storage appliance, backup product, container-orchestration cluster, firewall, database, or OT/industrial equipment) — route those to the appropriate other AIops-tools skill. Cloud IdPs (Okta, Entra ID, Auth0) are out of scope.\n  Governed identity operations with a built-in governance harness (audit, policy, token budget, undo, risk-tiers).\ninstaller:\n  kind: uv\n  package: identity-aiops\nargument-hint: \"[a user/client id, a realm, or describe your identity task]\"\nallowed-tools:\n  - Bash\nmetadata: {\"openclaw\":{\"requires\":{\"anyBins\":[\"identity-aiops\",\"uvx\"]},\"optional\":{\"env\":[\"IDENTITY_AIOPS_CONFIG\",\"IDENTITY_AIOPS_MASTER_PASSWORD\"]},\"homepage\":\"https://github.com/AIops-tools/Identity-AIops\",\"emoji\":\"🔐\",\"os\":[\"macos\",\"linux\"]}}\ncompatibility: >\n  Standalone, self-governed identity-provider operations across Keycloak (admin REST API /admin/realms/{realm}/..., OAuth2 client-credentials grant against the realm token endpoint with automatic refresh-on-401) and authentik (API v3 /api/v3/..., long-lived API token as a Bearer header). Each target in the config names its own platform, and a name-keyed platform registry selects the API shape, so the same tools work on both and one config can span a mixed estate. The governance harness (audit, policy, token/runaway budget, undo, risk-tiers) is bundled in the package — no external skill-family dependency.\n  All write operations are audited to a local SQLite DB under ~/.identity-aiops/ (relocatable via IDENTITY_AIOPS_HOME).\n  Credentials: the Keycloak confidential client's client secret or the authentik API token is stored ENCRYPTED in ~/.identity-aiops/secrets.enc (Fernet/AES-128 + scrypt-derived key) — never plaintext on disk. Run 'identity-aiops init' to onboard (it asks for the platform, base URL, and — Keycloak — realm + client_id), or 'identity-aiops secret set <target>' to add one. The store is unlocked by a master password from IDENTITY_AIOPS_MASTER_PASSWORD (non-interactive/MCP/CI) or an interactive prompt (CLI on a TTY). A legacy plaintext env var IDENTITY_<TARGET_NAME_UPPER>_SECRET is still honoured as a fallback with a deprecation warning (migrate with 'identity-aiops secret migrate'). Secrets are held only in memory, never logged or echoed; rotate_client_secret returns and records masked fingerprints only.\n  State-changing operations pass through the @governed_tool decorator (budget guard + audit + risk-tier labelling). enable_user, update_client_redirect_uris, and rotate_client_secret are risk=high with dry_run; revoke_user_sessions and rotate_client_secret are irreversible (priorState only). Reversible writes (disable_user/enable_user, require_password_reset, update_client_redirect_uris) capture the real fetched before-state and record an inverse undo descriptor. The tool records every call but does not decide whether a write is permitted — that is the agent's judgement or the connecting account's permissions.\n  Webhooks: none — no outbound network calls beyond the configured Keycloak / authentik REST API.\n  SSL: verify_ssl defaults to ON; disable only for self-signed lab certs.\n  Transitive dependencies: httpx (HTTP client) and the MCP SDK. No post-install scripts or background services.\n  Verification status: mock-validated; no recorded end-to-end run against a live IdP yet, and the modelled REST paths are the largest verification debt. Both Keycloak and authentik are free/self-hostable (each runs from a single container), so a lab is the cheapest live check. See docs/VERIFICATION.md.\n---\n\n# Identity AIops\n\n> **Disclaimer**: Community-maintained open-source project, **not affiliated with, endorsed by, or sponsored by the Keycloak project, Red Hat, Authentik Security Inc., or the authentik project.** Keycloak and authentik are trademarks of their respective owners. Source at [github.com/AIops-tools/Identity-AIops](https://github.com/AIops-tools/Identity-AIops) under the MIT license.\n\nGoverned identity operations — **29 MCP tools** across **Keycloak** (admin REST\n`/admin/realms/{realm}/...`) and **authentik** (API v3 `/api/v3/...`), every one\nwrapped with the bundled `@governed_tool` harness: a local unified audit log\nunder `~/.identity-aiops/`, policy engine, token/runaway budget guard,\nundo-token recording, and risk-tier labelling on the audit row. A per-target\n`platform` field selects the API shape, so the same tools work on both IdPs and\none config can span a mixed estate. The Keycloak client secret / authentik API\ntoken is stored **encrypted** (`~/.identity-aiops/secrets.enc`, Fernet +\nscrypt) — never plaintext on disk.\n\n> **Standalone**: the governance harness is bundled in the package\n> (`identity_aiops.governance`) — no external skill-family dependency. Both\n> platforms are free/self-hostable, so a self-hosted lab is the cheapest live\n> check; verification status and the checklist are in `docs/VERIFICATION.md`.\n\n## What This Skill Does\n\n| Group | Tools | Count | R/W |\n|-------|-------|:-----:|:---:|\n| **Realm / system** | identity_overview, realm_info, list_identity_providers | 3 | read |\n| **Users / groups** | list_users, user_detail, user_count, user_sessions, user_credentials, list_groups, group_members, user_lockout_status | 8 | read |\n| **Events** | login_events, admin_events | 2 | read |\n| **Clients** | list_clients, client_detail, client_sessions, client_session_stats | 4 | read |\n| **Flagship analyses** | login_failure_rca, stale_access_audit, client_misconfig_audit, mfa_coverage_analysis | 4 | read |\n| **Writes** | disable_user, revoke_user_sessions, require_password_reset | 3 | write (med) |\n| **Writes** | enable_user, update_client_redirect_uris, rotate_client_secret | 3 | write (**high**) |\n| **Undo** | undo_list, undo_apply | 2 | read + replay |\n\nThe four flagship analyses are transparent heuristics that report their numbers,\nnever a black-box verdict: `login_failure_rca` windows the failed-auth feed by\nuser/IP/client and separates password spray, targeted brute-force, a stale\nstored credential, a misconfigured client, an expired-credential storm, and a\nlockout storm; `stale_access_audit` flags dormant and never-used accounts,\ninteractive service accounts, and orphaned sessions; `client_misconfig_audit`\nranks clients by OAuth-BCP risk (wildcard/http redirects, secrets in public\nclients, implicit flow, missing PKCE, password grant); `mfa_coverage_analysis`\nreports second-factor coverage overall and per group.\n\n## Quick Install\n\n```bash\nuv tool install identity-aiops\nidentity-aiops init       # wizard: pick platform (keycloak/authentik) + encrypted secret\nidentity-aiops doctor\n```\n\nOr as an OpenClaw plugin, which installs this skill and its MCP server together:\n\n```bash\nopenclaw plugins install clawhub:@zw008/identity-aiops\nopenclaw skills info identity-aiops          # expect: Visible to model: yes\n```\n\nNeeds `uvx` on `PATH`: the MCP server is fetched with uv, pinned to this release.\n\n## When to Use This Skill\n\n- Get a one-shot snapshot (`overview` / `realm_info` / `user_count`)\n- Triage a login-failure or lockout storm (`login_failure_rca`) → cause + action\n- Run an access re-certification (`stale_access_audit`: idle users,\n  never-logged-in accounts, service-account misuse, orphaned sessions)\n- Audit OAuth clients (`client_misconfig_audit`: redirect URIs, PKCE, implicit\n  flow, password grant) and fix them (`update_client_redirect_uris`)\n- Measure and close the MFA gap (`mfa_coverage_analysis`, `user_credentials`)\n- Contain a compromised account (`disable_user` + `revoke_user_sessions` +\n  `require_password_reset`, all governed; re-enable is tagged high risk)\n- Rotate a leaked client secret (`rotate_client_secret`, high risk, masked)\n\n**Do NOT use when** the target is not a Keycloak/authentik IdP — route\nhypervisor, storage, backup, cluster, network/firewall, database, endpoint, or\nOT/industrial work to the appropriate other AIops-tools skill. Cloud IdPs\n(Okta, Entra ID, Auth0) are out of scope.\n\n## Related Skills — Skill Routing\n\n| If the user wants… | Use |\n|--------------------|-----|\n| Keycloak / authentik identity ops | **identity-aiops** (this skill) |\n| A non-identity platform (hypervisor, storage, backup, cluster, network device/controller, firewall, database, containers, endpoints, local LLM governance, compliance evidence) | the appropriate **other AIops-tools** skill (proxmox-aiops, truenas-aiops, ceph-aiops, veeam-aiops, k8s-aiops, network-aiops, fabric-aiops, firewall-aiops, postgres-aiops, container-host-aiops, endpoint-aiops, ai-guardian, compliance-aiops, …) |\n| Cloud IdPs (Okta, Entra ID, Auth0) | out of scope for this tool |\n\n## Common Workflows\n\nEach recipe starts from a read or one of the four RCAs and ends in a governed\nwrite. The **RCAs are MCP tools** (`login_failure_rca`, `stale_access_audit`,\n`client_misconfig_audit`, `mfa_coverage_analysis`) — call them through the MCP\nserver; the CLI covers the reads and the writes. Every CLI write accepts\n`--dry-run` and otherwise double-confirms.\n\n### 1. \"We're being brute-forced — contain it\"\n\n1. `identity-aiops overview` → how big is the failed-login feed right now, and\n   is this one account or the whole realm?\n2. MCP `login_failure_rca` → findings carrying their counts (the ordering is not on one\n   comparable quantity — see `references/agent-guardrails.md`), separating password\n   **spray** from one IP, **targeted** brute-force on one account, a client\n   failing with credential errors (a rotated secret not deployed), an\n   expired-credential storm, and a lockout storm.\n3. `identity-aiops events --type LOGIN_ERROR --user <username> -n 200` → the\n   raw failures behind the finding (authentik: `--type login_failed`).\n4. `identity-aiops users show <user-id>` and `identity-aiops users sessions\n   <user-id>` → is the account already compromised, i.e. did any attempt\n   actually succeed?\n5. Contain: `identity-aiops users disable <user-id> --dry-run`, then for real\n   (reversible — the fetched before-state is captured and an `enable_user`\n   inverse recorded).\n6. `identity-aiops users revoke-sessions <user-id>` → kill live sessions.\n   **Irreversible** (priorState only) — disabling alone does not end sessions\n   already issued, so this step is what actually stops the attacker.\n7. `identity-aiops undo list` → confirm the disable is reversible before you\n   hand off.\n\n**Failure branch**: if the RCA classifies it as a **misconfigured client**\nrather than an attack (mass credential errors from one client id), do not\ndisable users — you would lock out legitimate people while the real fault is a\nrotated secret that was never deployed. Go to recipe 3. If you disabled the\nwrong account, `identity-aiops users enable <user-id>` is **high** risk and\nneeds `IDENTITY_AUDIT_APPROVED_BY` + `IDENTITY_AUDIT_RATIONALE`, deliberately —\nre-enabling reverses containment.\n\n### 2. \"Quarterly access re-certification\"\n\n1. MCP `stale_access_audit` (e.g. `stale_days=90`) → dormant users with day\n   counts, never-logged-in accounts, service accounts being used\n   interactively, and orphaned sessions.\n2. `identity-aiops users list --search <name>` / `identity-aiops users show\n   <user-id>` → confirm each candidate is genuinely the account you think.\n3. `identity-aiops users sessions <user-id>` → check for a live session before\n   you touch a \"dormant\" account.\n4. Confirm with the account owner or its manager. Then, per account:\n   `identity-aiops users disable <user-id>` (reversible, undo-recorded).\n5. `identity-aiops users revoke-sessions <user-id>` for the orphaned sessions\n   the audit found (irreversible).\n6. Re-run `stale_access_audit` to confirm the list shrank as expected.\n\n**Failure branch**: an **interactive service account** finding is not a\ndisable candidate — disabling it takes down whatever integration depends on\nit. Trace the client first (`identity-aiops clients show <client-id>`,\n`identity-aiops clients list`) and fix the integration to stop using\ninteractive login. If a disable breaks something unexpectedly,\n`identity-aiops undo apply <id>` replays the captured prior state.\n\n### 3. \"Harden the OAuth clients before the audit\"\n\n1. MCP `client_misconfig_audit` → per-client `riskScore` with the evidence\n   behind it: wildcard or plain-`http` redirect URIs, a public client holding\n   a secret, implicit flow enabled, missing PKCE, password grant allowed.\n2. `identity-aiops clients show <client-id>` → the full current client\n   configuration, so you replace the right values.\n3. `identity-aiops clients set-redirect-uris <client-id> --uri\n   https://app.example.com/callback --dry-run` → note that `--uri` is repeated\n   and supplies the **FULL new list**, replacing what is there.\n4. Re-run without `--dry-run`: **high** risk, double confirm, requires\n   `IDENTITY_AUDIT_APPROVED_BY` + `IDENTITY_AUDIT_RATIONALE`. The prior URI\n   list is captured, so undo replays it exactly.\n5. If a secret leaked: `identity-aiops clients rotate-secret <client-id>`\n   (**high** risk, **irreversible**, masked priorState) — then deploy the new\n   secret everywhere that client is used.\n6. Re-run `client_misconfig_audit` to confirm the score dropped.\n\n**Failure branch**: rotating a secret before the deployments are ready is how\nyou cause recipe 1's \"misconfigured client\" storm — every service using the old\nsecret starts failing authentication immediately, and rotation cannot be\nundone. Stage the deployment first. If a redirect-URI replacement breaks a\nlogin flow, `identity-aiops undo apply <id>` restores the exact prior list;\nthis is why the URI change is reversible and the rotation is not.\n\n### 4. \"Show me who still has no second factor\"\n\n1. MCP `mfa_coverage_analysis` → coverage percentage, the worst groups first,\n   and the per-user gap list.\n2. `identity-aiops users credentials <user-id>` → what a specific user\n   actually has configured, so you distinguish \"no MFA\" from \"an enrolled\n   factor the analysis could not see\".\n3. `identity-aiops overview` and realm settings → confirm the realm's\n   brute-force protection and OTP policy actually require what you think they\n   require.\n4. Where a forced re-enrolment is part of the rollout:\n   `identity-aiops users require-reset <user-id> --dry-run`, then for real\n   (reversible — undo clears the pending requirement).\n5. `identity-aiops undo list` → confirm each reset flag can be cleared if the\n   rollout stalls.\n\n**Failure branch**: if a user is blocked out by the reset requirement (no\nworking recovery path, or they cannot complete enrolment),\n`identity-aiops users require-reset <user-id> --clear` removes the pending\nrequirement, and `identity-aiops undo apply <id>` does the same from the\nrecorded token. Do not chase a 100% coverage number by forcing resets on\nservice accounts — they have no interactive user to complete the flow, and the\n`stale_access_audit` in recipe 2 is the right tool for those.\n\n## Governance & Safety\n\nThe skill delivers reads and writes and records them; it does **not** decide\nwhether a write is permitted. That is your agent's judgement, or the permission\nof the account you connect it with (a Keycloak service account or authentik\ntoken without `manage-*` scope — writes then fail at the server). There is no\nread-only switch, policy file, or approval gate.\n\n- **Audit is the guarantee, and it is not bypassable.** Every call — MCP and\n  CLI alike — lands an audit row in `~/.identity-aiops/audit.db` (relocatable\n  via `IDENTITY_AIOPS_HOME`): params, status, and the risk tier.\n- `IDENTITY_AUDIT_APPROVED_BY` / `IDENTITY_AUDIT_RATIONALE` are optional\n  annotations recorded on the row (who/why); they are never required and never\n  block.\n- **Risk tier** — a descriptive label on the audit row derived from\n  `risk_level` (`enable_user`, `update_client_redirect_uris`,\n  `rotate_client_secret` = high; `disable_user`, `revoke_user_sessions`,\n  `require_password_reset` = medium); it gates nothing. Writes support\n  `--dry-run` and double confirmation at the CLI.\n- Reversible writes capture the real fetched before-state and record an\n  inverse descriptor (disable↔enable, reset-flag→clear, redirect-URI list\n  replay). `revoke_user_sessions` and `rotate_client_secret` are irreversible\n  (priorState only; secrets recorded masked).\n\n## References\n\n- `references/capabilities.md` — full tool + platform + API-path reference\n- `references/cli-reference.md` — CLI command reference\n- `references/setup-guide.md` — onboarding, credentials, and connectivity\n- `references/agent-guardrails.md` — running with a smaller / local model: the\n  truncation and null-field contracts, the Keycloak-vs-authentik tool\n  asymmetry, and a system prompt\n\nFile v0.8.5:_meta.json\n\n{\n  \"ownerId\": \"kn7b067awq2s97bn3d7p5qfhw5827pxc\",\n  \"slug\": \"identity-aiops\",\n  \"version\": \"0.8.5\",\n  \"publishedAt\": 1789601143154\n}\n\nFile v0.8.5:references/agent-guardrails.md\n\n# Agent guardrails — running identity-aiops with a smaller / local model\n\nIf you drive these tools with a local model (Llama, Qwen, Mistral … via Goose,\nOllama, LM Studio, or any OpenAI-compatible runtime), you will get noticeably\nbetter results with a short system prompt. This page gives you one, and — more\nimportantly — tells you which guardrails you **no longer need to write**, because\nthe tool now enforces them itself.\n\nThe distinction matters. A guardrail in a prompt is a request. A guardrail in the\nharness is a guarantee. Anything below that we could move into the harness, we did.\n\n## Authorization is not this tool's job — decide it where it belongs\n\nWhether a write should happen is your decision, or the account's. The tool does\nnot gate it — there is no read-only switch and no approval prompt to configure.\nThe two right places to control read vs write:\n\n- **The account you connect with.** Give the Keycloak service account (or the\n  authentik token) only the roles you want the agent to have — `view-users` /\n  `view-events` / `view-clients` and no `manage-*`. A write then fails at the\n  server, which is the only place the permission actually lives — no skill-side\n  flag can be argued around by a model, but a revoked permission cannot be.\n- **Your agent's system prompt.** If you want an observe-only session, tell the\n  model not to call the write tools (they are clearly tagged `[WRITE]`).\n\nWhat the tool *does* guarantee is that you can always see what happened:\n\n## What the tool enforces — do not waste prompt budget on these\n\n| You might be tempted to prompt | Why you don't need to |\n|---|---|\n| \"Don't invent a value when a field is missing\" | A field the IdP did not return comes back as `null`, never as `\"\"`. Absent and empty are distinguishable in the payload — a `lastLogin` of `null` means \"no sign-in on record\", not \"signed in at an empty time\". |\n| \"Tell me if the output was cut off\" | Every listing returns `{\"users\": [...], \"returned\": N, \"limit\": L, \"truncated\": true/false}` (same shape for `events`, `groups`, `members`, `clients`, `sessions`, `identityProviders`). Truncation is measured — one extra row is fetched — not guessed from a length coincidence. |\n| \"Tell me if the analysis only saw part of the data\" | The four analyses echo `inputsTruncated` / `feedTruncated`, and `truncated` + `maxRows` when a finding list was capped. The `*Count` fields are always the full totals. |\n| \"Make it show the number it judged on\" | `client_misconfig_audit` ranks clients by `riskScore` — the summed severity weights, echoed as `severityWeights` so the score is recomputable — and every finding carries its own `severity`. `login_failure_rca` findings each carry the counts that tripped them (`failures`, `distinctUsers`, `distinctIps`); the thresholds they were compared against are reported separately under `thresholds`, not on the finding. |\n| \"Confirm before anything destructive\" | Write CLI commands have `--dry-run` plus double confirmation. |\n| \"Log what you did\" | Every call is audited to `~/.identity-aiops/audit.db` regardless of what the model says it did. |\n\n## Platform asymmetry — a teaching error is an answer, not a failure\n\nidentity-aiops speaks to **two** identity providers through one tool set, and\nthey do not have the same APIs. Some tools exist only on one platform. When you\ncall one against the other platform, it returns a **teaching error** that names\nthe gap and points at the alternative.\n\n**That error is a definitive answer about the platform, not a broken tool.**\nDo not retry it, do not try a different argument, and do not report the tool as\nfailing. Switch approach, or tell the user the platform does not support it.\nThis is the single most common way a smaller model wastes a turn here.\n\n### Keycloak-only tools\n\nOn an **authentik** target these return `{\"error\": ...}`:\n\n| Tool | Why | What to do instead |\n|---|---|---|\n| `user_lockout_status` | authentik keeps no per-user brute-force lockout register | Use `login_failure_rca` over the failed-auth feed |\n| `client_sessions` | authentik has no per-provider session listing | Use `user_sessions` per user |\n| `client_session_stats` | authentik has no per-client session rollup | Use `user_sessions` per user, or `stale_access_audit` |\n| `require_password_reset` | authentik has no required-actions concept | Issue a recovery link from the authentik admin UI |\n| `rotate_client_secret` | authentik has no secret-rotation endpoint | Set a new client secret on the OAuth2 provider |\n\nThe two reads fail with `Resource '<name>' is not mapped for platform\n'authentik'. Mapped resources: ...`; the two writes fail with `<tool> is a\nKeycloak-only operation — authentik API v3 has no equivalent API. <hint>`.\n\n### authentik-only data\n\n`stale_access_audit` includes an `orphanedSessions` check that needs a\n**global** session list. Only authentik exposes one. On a **Keycloak** target\nthat check silently contributes nothing — `orphanedSessions` is always `[]` and\n`orphanedSessionCount` is always `0`. Do **not** report that as \"no orphaned\nsessions found\" on Keycloak; the check did not run. The other three findings in\nthat audit are unaffected.\n\n### Everything else works on both\n\n`identity_overview`, `realm_info`, `list_identity_providers`, `list_users`,\n`user_detail`, `user_count`, `user_sessions`, `user_credentials`, `list_groups`,\n`group_members`, `login_events`, `admin_events`, `list_clients`,\n`client_detail`, all four analyses, `disable_user`, `enable_user`,\n`revoke_user_sessions`, `update_client_redirect_uris`, `undo_list`,\n`undo_apply` — the normalized rows use the same field names on both platforms.\n\n## What still needs a prompt\n\nThese are model-behaviour problems the harness cannot fix from the outside.\n\n⚠️ **`login_failure_rca`'s order is not on one comparable quantity.** It does sort its findings\nworst-first, but the sort key falls back from `failures` to `distinctUsers`, so the two storm findings\n(`lockout-storm` and `expired-credential-storm`, neither of which has a `failures` key) are\nranked by a user count against another finding's failure count. Its findings carry neither a `rank` nor a `severity`. Weigh each\nfinding's own counts rather than its position. `client_misconfig_audit` is different: its\n`riskScore` ordering is stated in the payload and can be rechecked.\n\nCopy this into your agent's system prompt:\n\n```text\nYou operate a Keycloak or authentik identity provider through the\nidentity-aiops MCP tools.\n\nTOOL USE\n- Before answering any question about the current identity environment, you\n  MUST call a tool. Never answer from memory or assumption.\n- Actually invoke the tool. Do not describe the call you would make, and do not\n  emit an example JSON response in place of calling it.\n- If a tool call fails, report the real error verbatim. Never fill the gap with\n  a plausible-sounding answer.\n- Some tools are Keycloak-only and return an error explaining that on\n  authentik. That is a correct answer about the platform, not a tool failure:\n  do not retry it, and follow the alternative the error names.\n\nREADING RESULTS\n- Read the whole result before concluding. Listings return \"returned\", \"limit\",\n  and \"truncated\". If \"truncated\" is true, say so and re-run with a higher\n  limit instead of treating the partial result as complete.\n- `login_failure_rca` findings are not ranked on one comparable quantity and carry no rank.\n  Weigh each finding's own counts and say which one you acted on; never treat the first as\n  the headline.\n- The analyses return \"inputsTruncated\" / \"feedTruncated\". When either is true,\n  every count is a lower bound — a threshold may have gone unreached only\n  because the events that would have reached it were never fetched. Never\n  report a clipped analysis as an all-clear.\n- A null field means the IdP did not return that value. Report it as \"not\n  available\" — never infer it. A null lastLogin is \"no sign-in on record\"; a\n  null passwordPolicy is \"the realm did not report one\", not \"no policy\".\n- Report values exactly as returned. Do not normalise, translate, or prettify\n  usernames, event types, error codes, or ids.\n\nIDENTIFIERS — do not confuse these\n- A user id (Keycloak UUID, authentik integer pk) is not a username. Tools take\n  the id; get it from list_users.\n- A client's internal id (what client_detail and the client writes take) is not\n  its clientId (the public OAuth identifier shown to end users). list_clients\n  returns both.\n- A group id is not a group name or path.\n- A realm is a Keycloak concept. authentik has no realms; its target's realm\n  field is a label only.\n\nSCOPE\n- Separate observation from interpretation. State what the tools returned, then\n  any interpretation, clearly marked as such.\n- Do not assert that an account is compromised, dormant, or misconfigured\n  unless a tool result supports it. These conclusions get people locked out.\n- Do not add generic identity-security advice that does not follow from the\n  tool output.\n```\n\n## Recommended setup for a local model\n\nStart with a connection that *cannot* write, verify, and widen the account's\npermission only when you trust the setup. Identity writes are unusually\nconsequential — `disable_user` and `revoke_user_sessions` lock a person out of\neverything behind the IdP.\n\n```bash\n# Give the Keycloak service account only view-* roles (or an authentik token\n# without manage scope). A write then fails at the server, not on a flag a\n# model can argue around. Then:\nidentity-aiops doctor\n```\n\nOptionally annotate the audit trail with who is operating and why — recorded on\nevery row, never required:\n\n```bash\nexport IDENTITY_AUDIT_APPROVED_BY=\"your.name@example.com\"\nexport IDENTITY_AUDIT_RATIONALE=\"access review 2026-07-20\"\n```\n\n## If your model still struggles\n\nSome behaviours are model-capacity limits rather than prompt problems:\n\n- **Multi-tool workflows time out or drift.** Prefer the four analysis tools —\n  `login_failure_rca`, `stale_access_audit`, `client_misconfig_audit`,\n  `mfa_coverage_analysis` do the multi-step correlation inside one call, so the\n  model does not have to chain reads and keep user ids straight.\n- **The model ignores later tool results in a long context.** Event feeds are\n  the worst offender: `login_events` with the default `max_results=200` is a\n  lot of rows. Filter with `event_type` and `user`, and lower `max_results` —\n  the `truncated` flag will tell you when you cut too deep.\n- **The model reports \"no data\" from a long feed.** Check `returned` in the\n  reply it received; if it is non-zero, the model dropped the payload rather\n  than the tool returning nothing. Ask a narrower question.\n- **The model retries a Keycloak-only tool on authentik.** Put the\n  platform-asymmetry paragraph from the system prompt above near the *top* of\n  your prompt, not the bottom.\n- **The model describes calls instead of making them.** This is usually a\n  runtime/tool-calling-format mismatch, not a prompt problem — check that your\n  client advertises the tools in the format your model was trained on.\n\nFeedback on running this with a specific local model is genuinely useful —\nopen an issue at\n[github.com/AIops-tools/Identity-AIops](https://github.com/AIops-tools/Identity-AIops/issues)\nwith the model, runtime, and what went wrong.\n\nFile v0.8.5:references/capabilities.md\n\n# identity-aiops capabilities\n\n> **29 MCP tools** (21 read, 6 write, 2 undo) across Keycloak (admin REST `/admin/realms/{realm}/...`,\n> client-credentials grant, refresh-on-401) and authentik (API v3 `/api/v3/...`,\n> Bearer token). The concrete REST paths below are modelled from each project's\n> public API and need live verification.\n\nA per-target `platform` field (`keycloak` / `authentik`) selects the API shape;\nthe same tool name resolves to the right path on each IdP via the platform\nregistry. Every substituted path segment (realm, user id, client id) is\npercent-encoded centrally.\n\n## Realm / system (read)\n\n| Tool | Keycloak path | authentik path | Returns |\n|------|---------------|----------------|---------|\n| `identity_overview` | (composite) | (composite) | platform/realm, user/client/IdP counts, failed-login feed size |\n| `realm_info` | `/admin/realms/{realm}` | `/api/v3/admin/system/` | brute-force protection, password/OTP policy (KC); version/environment (AK) |\n| `list_identity_providers` | `/admin/realms/{realm}/identity-provider/instances` | `/api/v3/sources/all/` | federated IdPs / sources with enabled state |\n\n## Users / groups (read)\n\n| Tool | Keycloak path | authentik path | Returns |\n|------|---------------|----------------|---------|\n| `list_users` | `/admin/realms/{realm}/users` | `/api/v3/core/users/` | normalized users (id, username, enabled, lastLogin, serviceAccount) |\n| `user_detail` | `/admin/realms/{realm}/users/{id}` | `/api/v3/core/users/{id}/` | one user incl. requiredActions/attributes |\n| `user_count` | `/admin/realms/{realm}/users/count` | `/api/v3/core/users/` (pagination.count) | total users — the doctor probe |\n| `user_sessions` | `/admin/realms/{realm}/users/{id}/sessions` | `/api/v3/core/authenticated_sessions/?user=` | active sessions (id, IP, start/last access) |\n| `user_credentials` | `/admin/realms/{realm}/users/{id}/credentials` | `/api/v3/authenticators/admin/all/?user=` | credentials/devices with second-factor flags |\n| `list_groups` | `/admin/realms/{realm}/groups` | `/api/v3/core/groups/` | groups |\n| `group_members` | `/admin/realms/{realm}/groups/{id}/members` | `/api/v3/core/groups/{id}/` (users_obj) | normalized member users |\n| `user_lockout_status` | `/admin/realms/{realm}/attack-detection/brute-force/users/{id}` | — (teaching error) | failure count, locked state, last failure IP |\n\n## Events (read)\n\n| Tool | Keycloak path | authentik path | Returns |\n|------|---------------|----------------|---------|\n| `login_events` | `/admin/realms/{realm}/events` | `/api/v3/events/events/` | normalized events {time, type, user, ip, client, error} |\n| `admin_events` | `/admin/realms/{realm}/admin-events` | `/api/v3/events/events/` (admin actions) | admin/config changes {operation, resource, actor, ip} |\n\n## Clients (read)\n\n| Tool | Keycloak path | authentik path | Returns |\n|------|---------------|----------------|---------|\n| `list_clients` | `/admin/realms/{realm}/clients` | `/api/v3/providers/oauth2/` | normalized clients (public flag, redirect URIs, flows, PKCE) |\n| `client_detail` | `/admin/realms/{realm}/clients/{id}` | `/api/v3/providers/oauth2/{id}/` | one client normalized |\n| `client_sessions` | `/admin/realms/{realm}/clients/{id}/user-sessions` | — (teaching error) | sessions on one client |\n| `client_session_stats` | `/admin/realms/{realm}/client-session-stats` | — (teaching error) | active-session counts per client |\n\n## Flagship analyses (read, pure heuristics over the reads)\n\n| Tool | Feed | Findings |\n|------|------|----------|\n| `login_failure_rca` | failed-login events (windowed) | password-spray (one IP → many users), targeted-brute-force (many IPs → one user), stale-stored-credential (one IP → one user), misconfigured-client (client-credential errors), expired-credential-storm, lockout-storm — each with counts, cause, action; thresholds included in output |\n| `stale_access_audit` | users + successful logins + sessions | staleUsers (idle > N days), neverLoggedIn, serviceAccountsInteractive, orphanedSessions |\n| `client_misconfig_audit` | normalized clients | wildcard-redirect-uri, http-redirect-uri (non-localhost), public-client-with-secret, implicit-flow-enabled, public-client-missing-pkce, password-grant-enabled — ranked riskScore (high=30/med=15/low=5) |\n| `mfa_coverage_analysis` | users + per-user credentials | coverage % overall/per group, usersWithoutMfa; second factors = otp/totp/hotp/webauthn/duo/sms (confirmed) |\n\n## Writes (governed: dry_run preview, audit, undo where reversible)\n\n| Tool | Risk | Keycloak call | authentik call | Undo |\n|------|:----:|---------------|----------------|------|\n| `disable_user` | med | `PUT users/{id}` `{enabled:false}` | `PATCH core/users/{id}/` `{is_active:false}` | `enable_user` (only if it was enabled) |\n| `enable_user` | **high** | `PUT users/{id}` `{enabled:true}` | `PATCH core/users/{id}/` `{is_active:true}` | `disable_user` (only if it was disabled) |\n| `revoke_user_sessions` | med | `POST users/{id}/logout` | `DELETE authenticated_sessions/{sid}/` each | none — priorState sessionCount |\n| `require_password_reset` | med | `PUT users/{id}` requiredActions ± UPDATE_PASSWORD | — (teaching error) | itself with `clear=True` (only if this call set it) |\n| `update_client_redirect_uris` | **high** | `PUT clients/{id}` `{redirectUris}` | `PATCH providers/oauth2/{id}/` `{redirect_uris}` | itself with the prior list |\n| `rotate_client_secret` | **high** | `GET`+`POST clients/{id}/client-secret` | — (teaching error) | none — priorState **masked** fingerprint |\n\nRisk-tier rationale: containment/hygiene actions an operator needs promptly\n(disable, revoke, require-reset) sit at medium; access-granting or\nboundary-replacing actions (enable, redirect-URI replace, secret rotation) sit\nat high. The tier is a descriptive label carried onto the audit row, not a\ngate — whether a write runs is the agent's judgement or the connecting\naccount's permissions.\n\nFile v0.8.5:references/cli-reference.md\n\n# identity-aiops CLI reference\n\nAll read commands print normalized JSON. All write commands take `--dry-run`\n(preview, no call, no audit) and otherwise require **double confirmation**;\nconfirmed writes execute through the governed MCP twins, so they land in\n`~/.identity-aiops/audit.db` with undo where applicable. `--target/-t` selects\na target from config (default: the first one).\n\n## Setup / health\n\n```bash\nidentity-aiops init                 # onboarding wizard (platform, base URL, realm, secret)\nidentity-aiops doctor               # config + secrets + token acquisition + user-count probe\nidentity-aiops doctor --skip-auth   # config/secrets checks only (no network)\nidentity-aiops overview             # one-shot estate summary\nidentity-aiops mcp                  # start the MCP server (stdio)\n```\n\n## Secrets (encrypted store)\n\n```bash\nidentity-aiops secret set <target>    # store/replace a secret (hidden prompt)\nidentity-aiops secret list            # target names only — never values\nidentity-aiops secret remove <target>\nidentity-aiops secret migrate         # legacy .env / env vars → secrets.enc\n```\n\nMaster password: `IDENTITY_AIOPS_MASTER_PASSWORD` (non-interactive/MCP) or an\ninteractive prompt on a TTY.\n\n## Events\n\n```bash\nidentity-aiops events                          # recent auth events\nidentity-aiops events --type LOGIN_ERROR -n 50 # Keycloak failed logins\nidentity-aiops events --type login_failed      # authentik failed logins\nidentity-aiops events --user alice\n```\n\n## Users\n\n```bash\nidentity-aiops users list [--search alice] [--limit 200]\nidentity-aiops users show <user-id>\nidentity-aiops users sessions <user-id>\nidentity-aiops users credentials <user-id>          # MFA surface\n\n# governed writes\nidentity-aiops users disable <user-id> [--dry-run]          # med, undo: enable\nidentity-aiops users enable <user-id> [--dry-run]           # HIGH\nidentity-aiops users revoke-sessions <user-id> [--dry-run]  # med, irreversible\nidentity-aiops users require-reset <user-id> [--clear] [--dry-run]\n```\n\n## Clients\n\n```bash\nidentity-aiops clients list [--limit 200]\nidentity-aiops clients show <client-id>\n\n# governed writes\nidentity-aiops clients set-redirect-uris <client-id> -u https://a/cb -u https://b/cb [--dry-run]  # HIGH\nidentity-aiops clients rotate-secret <client-id> [--dry-run]                                       # HIGH, masked\n```\n\n## Environment variables\n\n| Variable | Purpose |\n|----------|---------|\n| `IDENTITY_AIOPS_HOME` | relocate all state (config, secrets, audit, undo) |\n| `IDENTITY_AIOPS_CONFIG` | alternate config.yaml path (MCP server) |\n| `IDENTITY_AIOPS_MASTER_PASSWORD` | unlock secrets.enc non-interactively |\n| `IDENTITY_AUDIT_APPROVED_BY` / `IDENTITY_AUDIT_RATIONALE` | optional audit annotations (who/why), recorded when set |\n| `IDENTITY_MAX_TOOL_CALLS` / `IDENTITY_MAX_TOOL_SECONDS` | session budget ceilings |\n| `IDENTITY_<TARGET>_SECRET` | legacy plaintext secret fallback (deprecated) |\n\nFile v0.8.5:references/setup-guide.md\n\n# identity-aiops setup & security guide\n\n> Verification status: mock-validated; no recorded live IdP run yet. Both **Keycloak**\n> and **authentik** are free/self-hostable (each runs from a single container), so a lab is\n> the easiest live check. The modelled REST paths are the largest verification\n> debt.\n\n## 1. Install\n\n```bash\nuv tool install identity-aiops       # or: pipx install identity-aiops\n```\n\n## 2. What you need per IdP\n\n- **Keycloak** — a **confidential client** with *Client authentication* ON and\n  *Service accounts roles* enabled (Clients → Create client). Grant its service\n  account the `realm-management` roles the agent should have:\n  - reads/analyses only: `view-users`, `view-events`, `view-clients`,\n    `view-realm`, `view-identity-providers`\n  - governed writes too: add `manage-users` and/or `manage-clients`\n  identity-aiops exchanges the client's **client_id + secret** at\n  `/realms/{realm}/protocol/openid-connect/token` (client-credentials grant)\n  and refreshes the short-lived token automatically on a 401.\n- **authentik** — an **API token** (Directory → Tokens & App passwords) for a\n  least-privileged admin user. The token is sent as `Authorization: Bearer` on\n  every call.\n\n## 3. Onboard with the wizard\n\n```bash\nidentity-aiops init\n```\n\nThe wizard asks, per target, for the **platform** (`keycloak` / `authentik`),\nthe **base URL** (e.g. `https://sso.example.com`), TLS verification (default\n**ON**; answer No only for self-signed lab certs), and — Keycloak only — the\n**realm** (default `master`) and the **client_id** (saved as `username`). The\nsecret (client secret / API token) goes **encrypted** into\n`~/.identity-aiops/secrets.enc`; non-secret details go to\n`~/.identity-aiops/config.yaml`.\n\nExample `config.yaml`:\n\n```yaml\ntargets:\n  - name: sso1\n    platform: keycloak\n    base_url: https://sso.example.com\n    realm: master\n    username: identity-aiops-agent\n    verify_ssl: true\n  - name: ak1\n    platform: authentik\n    base_url: https://auth.example.com\n    verify_ssl: true\n```\n\n## 4. Verify\n\n```bash\nidentity-aiops doctor\n```\n\nDoctor checks the config, the encrypted store (and its permissions), then per\ntarget runs the full auth path (Keycloak token acquisition / authentik bearer)\nplus a cheap realm probe — the user count. Exit code 0 = healthy.\n\n## 5. MCP client configuration\n\n```json\n{\n  \"mcpServers\": {\n    \"identity-aiops\": {\n      \"command\": \"uvx\",\n      \"args\": [\"--from\", \"identity-aiops\", \"identity-aiops-mcp\"],\n      \"env\": {\n        \"IDENTITY_AIOPS_MASTER_PASSWORD\": \"<master password>\",\n        \"IDENTITY_AUDIT_APPROVED_BY\": \"<optional: attributed on audit rows>\"\n      }\n    }\n  }\n}\n```\n\nMCP clients start the server with a minimal environment — shell-profile\nvariables are NOT inherited; put everything the server needs in the `env`\nblock.\n\n## 6. Security notes\n\n- Secrets: Fernet-encrypted (scrypt-derived key), chmod 600, never plaintext;\n  legacy `IDENTITY_<TARGET>_SECRET` env fallback warns and should be migrated\n  (`identity-aiops secret migrate`).\n- Least privilege: scope the Keycloak service account / authentik token to the\n  roles you actually want the agent to exercise — the reads/analyses work with\n  view-only roles.\n- High-risk writes (`enable_user`, `update_client_redirect_uris`,\n  `rotate_client_secret`) are tagged risk=high on the audit row; whether they\n  run is the connecting account's permissions or your agent's judgement, not a\n  tool-side gate. `IDENTITY_AUDIT_APPROVED_BY` / `IDENTITY_AUDIT_RATIONALE` are\n  optional annotations recorded when set.\n- `rotate_client_secret` never shows a secret — fetch the new value from the\n  admin console over a trusted channel.\n- Audit/undo live in `~/.identity-aiops/` (`audit.db`, `undo.db`), relocatable\n  via `IDENTITY_AIOPS_HOME`.\n\nFile v0.8.5:skill-card.md\n\n## Description:\n\nIdentity AIops helps agents operate Keycloak and authentik identity providers for user, event, client, MFA, root-cause analysis, and governed write workflows.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[zw008](https://clawhub.ai/user/zw008)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers, identity administrators, and security operators use this skill to inspect and administer Keycloak or authentik estates, triage login and lockout incidents, audit stale access and OAuth clients, measure MFA coverage, and perform governed containment changes.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: High-impact identity-provider writes can disable or enable users, revoke sessions, require password resets, replace redirect URIs, or rotate client secrets without a tool-enforced approval gate.\n\nMitigation: Run the skill with a least-privilege Keycloak service account or authentik token, start with view-only roles, use dry-run where available, and grant manage-users or manage-clients only after operator approval.\n\nRisk: Audit rows and risk labels record activity but do not block unsafe or unauthorized actions.\n\nMitigation: Enforce authorization through IdP permissions and agent operating procedures, and review the local audit log after sensitive workflows.\n\nRisk: The artifact says live IdP validation has not been recorded and modeled REST paths remain verification debt.\n\nMitigation: Validate against a self-hosted Keycloak or authentik lab and run the doctor check before using the skill against production identity infrastructure.\n\nRisk: Client secret rotation and session revocation are irreversible workflows.\n\nMitigation: Stage dependent service changes before rotating secrets and confirm session-revocation targets with read commands before executing writes.\n\n## Reference(s):\n\n- [ClawHub Skill Page](https://clawhub.ai/zw008/skills/identity-aiops)\n- [Project Homepage](https://github.com/AIops-tools/Identity-AIops)\n- [capabilities.md](references/capabilities.md)\n- [cli-reference.md](references/cli-reference.md)\n- [setup-guide.md](references/setup-guide.md)\n- [agent-guardrails.md](references/agent-guardrails.md)\n\n## Skill Output:\n\n**Output Type(s):** [Text, Markdown, Shell commands, Configuration, Guidance]\n\n**Output Format:** [Markdown guidance with inline shell commands and JSON or configuration snippets]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Read commands return normalized JSON; write workflows expose dry-run support, risk labels, and audit records.]\n\n## Skill Version(s):\n\n0.8.5 (source: server release evidence)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v0.8.4: 7 files, 19665 bytes\n\nFiles: references/agent-guardrails.md (10399b), references/capabilities.md (5977b), references/cli-reference.md (2965b), references/setup-guide.md (3798b), skill-card.md (2589b), SKILL.md (17809b), _meta.json (133b)\n\nFile v0.8.4:SKILL.md\n\n---\nname: identity-aiops\nslug: identity-aiops\ndisplayName: \"Identity AIops\"\nsummary: \"Governed Keycloak + authentik identity ops: users, events, clients, MFA, RCA. 29 tools.\"\nlicense: MIT\nhomepage: https://github.com/AIops-tools/Identity-AIops\ntags: [aiops, mcp, governance, identity]\ndescription: >\n  Use this skill whenever the user needs to operate a Keycloak or authentik identity provider — a one-shot overview, realm settings, users with sessions/credentials/groups/lockout status, authentication and admin events, OAuth/OIDC clients, four flagship RCAs (login-failure/lockout-storm, stale access, client misconfiguration, MFA coverage), and governed writes (disable/enable a user, revoke sessions, require a password reset, replace redirect URIs, rotate a client secret).\n  Always use this skill for \"Keycloak\", \"authentik\", \"realm\", \"SSO users\", \"login failures\", \"brute force logins\", \"locked out users\", \"stale accounts\", \"service account misuse\", \"redirect URI\", \"PKCE\", \"implicit flow\", \"client secret rotation\", \"MFA coverage\", \"who has no 2FA\" when the context is a Keycloak/authentik IdP.\n  Do NOT use when the target is something other than a Keycloak/authentik identity provider (a hypervisor, storage appliance, backup product, container-orchestration cluster, firewall, database, or OT/industrial equipment) — route those to the appropriate other AIops-tools skill. Cloud IdPs (Okta, Entra ID, Auth0) are out of scope.\n  Governed identity operations with a built-in governance harness (audit, policy, token budget, undo, risk-tiers).\ninstaller:\n  kind: uv\n  package: identity-aiops\nargument-hint: \"[a user/client id, a realm, or describe your identity task]\"\nallowed-tools:\n  - Bash\nmetadata: {\"openclaw\":{\"requires\":{\"anyBins\":[\"identity-aiops\",\"uvx\"]},\"optional\":{\"env\":[\"IDENTITY_AIOPS_CONFIG\",\"IDENTITY_AIOPS_MASTER_PASSWORD\"]},\"homepage\":\"https://github.com/AIops-tools/Identity-AIops\",\"emoji\":\"🔐\",\"os\":[\"macos\",\"linux\"]}}\ncompatibility: >\n  Standalone, self-governed identity-provider operations across Keycloak (admin REST API /admin/realms/{realm}/..., OAuth2 client-credentials grant against the realm token endpoint with automatic refresh-on-401) and authentik (API v3 /api/v3/..., long-lived API token as a Bearer header). Each target in the config names its own platform, and a name-keyed platform registry selects the API shape, so the same tools work on both and one config can span a mixed estate. The governance harness (audit, policy, token/runaway budget, undo, risk-tiers) is bundled in the package — no external skill-family dependency.\n  All write operations are audited to a local SQLite DB under ~/.identity-aiops/ (relocatable via IDENTITY_AIOPS_HOME).\n  Credentials: the Keycloak confidential client's client secret or the authentik API token is stored ENCRYPTED in ~/.identity-aiops/secrets.enc (Fernet/AES-128 + scrypt-derived key) — never plaintext on disk. Run 'identity-aiops init' to onboard (it asks for the platform, base URL, and — Keycloak — realm + client_id), or 'identity-aiops secret set <target>' to add one. The store is unlocked by a master password from IDENTITY_AIOPS_MASTER_PASSWORD (non-interactive/MCP/CI) or an interactive prompt (CLI on a TTY). A legacy plaintext env var IDENTITY_<TARGET_NAME_UPPER>_SECRET is still honoured as a fallback with a deprecation warning (migrate with 'identity-aiops secret migrate'). Secrets are held only in memory, never logged or echoed; rotate_client_secret returns and records masked fingerprints only.\n  State-changing operations pass through the @governed_tool decorator (budget guard + audit + risk-tier labelling). enable_user, update_client_redirect_uris, and rotate_client_secret are risk=high with dry_run; revoke_user_sessions and rotate_client_secret are irreversible (priorState only). Reversible writes (disable_user/enable_user, require_password_reset, update_client_redirect_uris) capture the real fetched before-state and record an inverse undo descriptor. The tool records every call but does not decide whether a write is permitted — that is the agent's judgement or the connecting account's permissions.\n  Webhooks: none — no outbound network calls beyond the configured Keycloak / authentik REST API.\n  SSL: verify_ssl defaults to ON; disable only for self-signed lab certs.\n  Transitive dependencies: httpx (HTTP client) and the MCP SDK. No post-install scripts or background services.\n  Verification status: mock-validated; no recorded end-to-end run against a live IdP yet, and the modelled REST paths are the largest verification debt. Both Keycloak and authentik are free/self-hostable (each runs from a single container), so a lab is the cheapest live check. See docs/VERIFICATION.md.\n---\n\n# Identity AIops\n\n> **Disclaimer**: Community-maintained open-source project, **not affiliated with, endorsed by, or sponsored by the Keycloak project, Red Hat, Authentik Security Inc., or the authentik project.** Keycloak and authentik are trademarks of their respective owners. Source at [github.com/AIops-tools/Identity-AIops](https://github.com/AIops-tools/Identity-AIops) under the MIT license.\n\nGoverned identity operations — **29 MCP tools** across **Keycloak** (admin REST\n`/admin/realms/{realm}/...`) and **authentik** (API v3 `/api/v3/...`), every one\nwrapped with the bundled `@governed_tool` harness: a local unified audit log\nunder `~/.identity-aiops/`, policy engine, token/runaway budget guard,\nundo-token recording, and risk-tier labelling on the audit row. A per-target\n`platform` field selects the API shape, so the same tools work on both IdPs and\none config can span a mixed estate. The Keycloak client secret / authentik API\ntoken is stored **encrypted** (`~/.identity-aiops/secrets.enc`, Fernet +\nscrypt) — never plaintext on disk.\n\n> **Standalone**: the governance harness is bundled in the package\n> (`identity_aiops.governance`) — no external skill-family dependency. Both\n> platforms are free/self-hostable, so a self-hosted lab is the cheapest live\n> check; verification status and the checklist are in `docs/VERIFICATION.md`.\n\n## What This Skill Does\n\n| Group | Tools | Count | R/W |\n|-------|-------|:-----:|:---:|\n| **Realm / system** | identity_overview, realm_info, list_identity_providers | 3 | read |\n| **Users / groups** | list_users, user_detail, user_count, user_sessions, user_credentials, list_groups, group_members, user_lockout_status | 8 | read |\n| **Events** | login_events, admin_events | 2 | read |\n| **Clients** | list_clients, client_detail, client_sessions, client_session_stats | 4 | read |\n| **Flagship analyses** | login_failure_rca, stale_access_audit, client_misconfig_audit, mfa_coverage_analysis | 4 | read |\n| **Writes** | disable_user, revoke_user_sessions, require_password_reset | 3 | write (med) |\n| **Writes** | enable_user, update_client_redirect_uris, rotate_client_secret | 3 | write (**high**) |\n| **Undo** | undo_list, undo_apply | 2 | read + replay |\n\nThe four flagship analyses are transparent heuristics that report their numbers,\nnever a black-box verdict: `login_failure_rca` windows the failed-auth feed by\nuser/IP/client and separates password spray, targeted brute-force, a stale\nstored credential, a misconfigured client, an expired-credential storm, and a\nlockout storm; `stale_access_audit` flags dormant and never-used accounts,\ninteractive service accounts, and orphaned sessions; `client_misconfig_audit`\nranks clients by OAuth-BCP risk (wildcard/http redirects, secrets in public\nclients, implicit flow, missing PKCE, password grant); `mfa_coverage_analysis`\nreports second-factor coverage overall and per group.\n\n## Quick Install\n\n```bash\nuv tool install identity-aiops\nidentity-aiops init       # wizard: pick platform (keycloak/authentik) + encrypted secret\nidentity-aiops doctor\n```\n\nOr as an OpenClaw plugin, which installs this skill and its MCP server together:\n\n```bash\nopenclaw plugins install clawhub:@zw008/identity-aiops\nopenclaw skills info identity-aiops          # expect: Visible to model: yes\n```\n\nNeeds `uvx` on `PATH`: the MCP server is fetched with uv, pinned to this release.\n\n## When to Use This Skill\n\n- Get a one-shot snapshot (`overview` / `realm_info` / `user_count`)\n- Triage a login-failure or lockout storm (`login_failure_rca`) → cause + action\n- Run an access re-certification (`stale_access_audit`: idle users,\n  never-logged-in accounts, service-account misuse, orphaned sessions)\n- Audit OAuth clients (`client_misconfig_audit`: redirect URIs, PKCE, implicit\n  flow, password grant) and fix them (`update_client_redirect_uris`)\n- Measure and close the MFA gap (`mfa_coverage_analysis`, `user_credentials`)\n- Contain a compromised account (`disable_user` + `revoke_user_sessions` +\n  `require_password_reset`, all governed; re-enable is tagged high risk)\n- Rotate a leaked client secret (`rotate_client_secret`, high risk, masked)\n\n**Do NOT use when** the target is not a Keycloak/authentik IdP — route\nhypervisor, storage, backup, cluster, network/firewall, database, endpoint, or\nOT/industrial work to the appropriate other AIops-tools skill. Cloud IdPs\n(Okta, Entra ID, Auth0) are out of scope.\n\n## Related Skills — Skill Routing\n\n| If the user wants… | Use |\n|--------------------|-----|\n| Keycloak / authentik identity ops | **identity-aiops** (this skill) |\n| A non-identity platform (hypervisor, storage, backup, cluster, network device/controller, firewall, database, containers, endpoints, local LLM governance, compliance evidence) | the appropriate **other AIops-tools** skill (proxmox-aiops, truenas-aiops, ceph-aiops, veeam-aiops, k8s-aiops, network-aiops, fabric-aiops, firewall-aiops, postgres-aiops, container-host-aiops, endpoint-aiops, ai-guardian, compliance-aiops, …) |\n| Cloud IdPs (Okta, Entra ID, Auth0) | out of scope for this tool |\n\n## Common Workflows\n\nEach recipe starts from a read or one of the four RCAs and ends in a governed\nwrite. The **RCAs are MCP tools** (`login_failure_rca`, `stale_access_audit`,\n`client_misconfig_audit`, `mfa_coverage_analysis`) — call them through the MCP\nserver; the CLI covers the reads and the writes. Every CLI write accepts\n`--dry-run` and otherwise double-confirms.\n\n### 1. \"We're being brute-forced — contain it\"\n\n1. `identity-aiops overview` → how big is the failed-login feed right now, and\n   is this one account or the whole realm?\n2. MCP `login_failure_rca` → findings ranked with numbers, separating password\n   **spray** from one IP, **targeted** brute-force on one account, a client\n   failing with credential errors (a rotated secret not deployed), an\n   expired-credential storm, and a lockout storm.\n3. `identity-aiops events --type LOGIN_ERROR --user <username> -n 200` → the\n   raw failures behind the finding (authentik: `--type login_failed`).\n4. `identity-aiops users show <user-id>` and `identity-aiops users sessions\n   <user-id>` → is the account already compromised, i.e. did any attempt\n   actually succeed?\n5. Contain: `identity-aiops users disable <user-id> --dry-run`, then for real\n   (reversible — the fetched before-state is captured and an `enable_user`\n   inverse recorded).\n6. `identity-aiops users revoke-sessions <user-id>` → kill live sessions.\n   **Irreversible** (priorState only) — disabling alone does not end sessions\n   already issued, so this step is what actually stops the attacker.\n7. `identity-aiops undo list` → confirm the disable is reversible before you\n   hand off.\n\n**Failure branch**: if the RCA classifies it as a **misconfigured client**\nrather than an attack (mass credential errors from one client id), do not\ndisable users — you would lock out legitimate people while the real fault is a\nrotated secret that was never deployed. Go to recipe 3. If you disabled the\nwrong account, `identity-aiops users enable <user-id>` is **high** risk and\nneeds `IDENTITY_AUDIT_APPROVED_BY` + `IDENTITY_AUDIT_RATIONALE`, deliberately —\nre-enabling reverses containment.\n\n### 2. \"Quarterly access re-certification\"\n\n1. MCP `stale_access_audit` (e.g. `stale_days=90`) → dormant users with day\n   counts, never-logged-in accounts, service accounts being used\n   interactively, and orphaned sessions.\n2. `identity-aiops users list --search <name>` / `identity-aiops users show\n   <user-id>` → confirm each candidate is genuinely the account you think.\n3. `identity-aiops users sessions <user-id>` → check for a live session before\n   you touch a \"dormant\" account.\n4. Confirm with the account owner or its manager. Then, per account:\n   `identity-aiops users disable <user-id>` (reversible, undo-recorded).\n5. `identity-aiops users revoke-sessions <user-id>` for the orphaned sessions\n   the audit found (irreversible).\n6. Re-run `stale_access_audit` to confirm the list shrank as expected.\n\n**Failure branch**: an **interactive service account** finding is not a\ndisable candidate — disabling it takes down whatever integration depends on\nit. Trace the client first (`identity-aiops clients show <client-id>`,\n`identity-aiops clients list`) and fix the integration to stop using\ninteractive login. If a disable breaks something unexpectedly,\n`identity-aiops undo apply <id>` replays the captured prior state.\n\n### 3. \"Harden the OAuth clients before the audit\"\n\n1. MCP `client_misconfig_audit` → per-client `riskScore` with the evidence\n   behind it: wildcard or plain-`http` redirect URIs, a public client holding\n   a secret, implicit flow enabled, missing PKCE, password grant allowed.\n2. `identity-aiops clients show <client-id>` → the full current client\n   configuration, so you replace the right values.\n3. `identity-aiops clients set-redirect-uris <client-id> --uri\n   https://app.example.com/callback --dry-run` → note that `--uri` is repeated\n   and supplies the **FULL new list**, replacing what is there.\n4. Re-run without `--dry-run`: **high** risk, double confirm, requires\n   `IDENTITY_AUDIT_APPROVED_BY` + `IDENTITY_AUDIT_RATIONALE`. The prior URI\n   list is captured, so undo replays it exactly.\n5. If a secret leaked: `identity-aiops clients rotate-secret <client-id>`\n   (**high** risk, **irreversible**, masked priorState) — then deploy the new\n   secret everywhere that client is used.\n6. Re-run `client_misconfig_audit` to confirm the score dropped.\n\n**Failure branch**: rotating a secret before the deployments are ready is how\nyou cause recipe 1's \"misconfigured client\" storm — every service using the old\nsecret starts failing authentication immediately, and rotation cannot be\nundone. Stage the deployment first. If a redirect-URI replacement breaks a\nlogin flow, `identity-aiops undo apply <id>` restores the exact prior list;\nthis is why the URI change is reversible and the rotation is not.\n\n### 4. \"Show me who still has no second factor\"\n\n1. MCP `mfa_coverage_analysis` → coverage percentage, the worst groups first,\n   and the per-user gap list.\n2. `identity-aiops users credentials <user-id>` → what a specific user\n   actually has configured, so you distinguish \"no MFA\" from \"an enrolled\n   factor the analysis could not see\".\n3. `identity-aiops overview` and realm settings → confirm the realm's\n   brute-force protection and OTP policy actually require what you think they\n   require.\n4. Where a forced re-enrolment is part of the rollout:\n   `identity-aiops users require-reset <user-id> --dry-run`, then for real\n   (reversible — undo clears the pending requirement).\n5. `identity-aiops undo list` → confirm each reset flag can be cleared if the\n   rollout stalls.\n\n**Failure branch**: if a user is blocked out by the reset requirement (no\nworking recovery path, or they cannot complete enrolment),\n`identity-aiops users require-reset <user-id> --clear` removes the pending\nrequirement, and `identity-aiops undo apply <id>` does the same from the\nrecorded token. Do not chase a 100% coverage number by forcing resets on\nservice accounts — they have no interactive user to complete the flow, and the\n`stale_access_audit` in recipe 2 is the right tool for those.\n\n## Governance & Safety\n\nThe skill delivers reads and writes and records them; it does **not** decide\nwhether a write is permitted. That is your agent's judgement, or the permission\nof the account you connect it with (a Keycloak service account or authentik\ntoken without `manage-*` scope — writes then fail at the server). There is no\nread-only switch, policy file, or approval gate.\n\n- **Audit is the guarantee, and it is not bypassable.** Every call — MCP and\n  CLI alike — lands an audit row in `~/.identity-aiops/audit.db` (relocatable\n  via `IDENTITY_AIOPS_HOME`): params, status, and the risk tier.\n- `IDENTITY_AUDIT_APPROVED_BY` / `IDENTITY_AUDIT_RATIONALE` are optional\n  annotations recorded on the row (who/why); they are never required and never\n  block.\n- **Risk tier** — a descriptive label on the audit row derived from\n  `risk_level` (`enable_user`, `update_client_redirect_uris`,\n  `rotate_client_secret` = high; `disable_user`, `revoke_user_sessions`,\n  `require_password_reset` = medium); it gates nothing. Writes support\n  `--dry-run` and double confirmation at the CLI.\n- Reversible writes capture the real fetched before-state and record an\n  inverse descriptor (disable↔enable, reset-flag→clear, redirect-URI list\n  replay). `revoke_user_sessions` and `rotate_client_secret` are irreversible\n  (priorState only; secrets recorded masked).\n\n## References\n\n- `references/capabilities.md` — full tool + platform + API-path reference\n- `references/cli-reference.md` — CLI command reference\n- `references/setup-guide.md` — onboarding, credentials, and connectivity\n- `references/agent-guardrails.md` — running with a smaller / local model: the\n  truncation and null-field contracts, the Keycloak-vs-authentik tool\n  asymmetry, and a system prompt\n\nFile v0.8.4:_meta.json\n\n{\n  \"ownerId\": \"kn7b067awq2s97bn3d7p5qfhw5827pxc\",\n  \"slug\": \"identity-aiops\",\n  \"version\": \"0.8.4\",\n  \"publishedAt\": 1789535705770\n}\n\nFile v0.8.4:references/agent-guardrails.md\n\n# Agent guardrails — running identity-aiops with a smaller / local model\n\nIf you drive these tools with a local model (Llama, Qwen, Mistral … via Goose,\nOllama, LM Studio, or any OpenAI-compatible runtime), you will get noticeably\nbetter results with a short system prompt. This page gives you one, and — more\nimportantly — tells you which guardrails you **no longer need to write**, because\nthe tool now enforces them itself.\n\nThe distinction matters. A guardrail in a prompt is a request. A guardrail in the\nharness is a guarantee. Anything below that we could move into the harness, we did.\n\n## Authorization is not this tool's job — decide it where it belongs\n\nWhether a write should happen is your decision, or the account's. The tool does\nnot gate it — there is no read-only switch and no approval prompt to configure.\nThe two right places to control read vs write:\n\n- **The account you connect with.** Give the Keycloak service account (or the\n  authentik token) only the roles you want the agent to have — `view-users` /\n  `view-events` / `view-clients` and no `manage-*`. A write then fails at the\n  server, which is the only place the permission actually lives — no skill-side\n  flag can be argued around by a model, but a revoked permission cannot be.\n- **Your agent's system prompt.** If you want an observe-only session, tell the\n  model not to call the write tools (they are clearly tagged `[WRITE]`).\n\nWhat the tool *does* guarantee is that you can always see what happened:\n\n## What the tool enforces — do not waste prompt budget on these\n\n| You might be tempted to prompt | Why you don't need to |\n|---|---|\n| \"Don't invent a value when a field is missing\" | A field the IdP did not return comes back as `null`, never as `\"\"`. Absent and empty are distinguishable in the payload — a `lastLogin` of `null` means \"no sign-in on record\", not \"signed in at an empty time\". |\n| \"Tell me if the output was cut off\" | Every listing returns `{\"users\": [...], \"returned\": N, \"limit\": L, \"truncated\": true/false}` (same shape for `events`, `groups`, `members`, `clients`, `sessions`, `identityProviders`). Truncation is measured — one extra row is fetched — not guessed from a length coincidence. |\n| \"Tell me if the analysis only saw part of the data\" | The four analyses echo `inputsTruncated` / `feedTruncated`, and `truncated` + `maxRows` when a finding list was capped. The `*Count` fields are always the full totals. |\n| \"Preserve the ordering / tell me what's most urgent\" | `client_misconfig_audit` ranks by `riskScore` with the severity weights in the payload; `login_failure_rca` sorts findings worst-first and every finding carries the numbers that tripped it. Priority is in the payload, not implied by list position. |\n| \"Confirm before anything destructive\" | Write CLI commands have `--dry-run` plus double confirmation. |\n| \"Log what you did\" | Every call is audited to `~/.identity-aiops/audit.db` regardless of what the model says it did. |\n\n## Platform asymmetry — a teaching error is an answer, not a failure\n\nidentity-aiops speaks to **two** identity providers through one tool set, and\nthey do not have the same APIs. Some tools exist only on one platform. When you\ncall one against the other platform, it returns a **teaching error** that names\nthe gap and points at the alternative.\n\n**That error is a definitive answer about the platform, not a broken tool.**\nDo not retry it, do not try a different argument, and do not report the tool as\nfailing. Switch approach, or tell the user the platform does not support it.\nThis is the single most common way a smaller model wastes a turn here.\n\n### Keycloak-only tools\n\nOn an **authentik** target these return `{\"error\": ...}`:\n\n| Tool | Why | What to do instead |\n|---|---|---|\n| `user_lockout_status` | authentik keeps no per-user brute-force lockout register | Use `login_failure_rca` over the failed-auth feed |\n| `client_sessions` | authentik has no per-provider session listing | Use `user_sessions` per user |\n| `client_session_stats` | authentik has no per-client session rollup | Use `user_sessions` per user, or `stale_access_audit` |\n| `require_password_reset` | authentik has no required-actions concept | Issue a recovery link from the authentik admin UI |\n| `rotate_client_secret` | authentik has no secret-rotation endpoint | Set a new client secret on the OAuth2 provider |\n\nThe two reads fail with `Resource '<name>' is not mapped for platform\n'authentik'. Mapped resources: ...`; the two writes fail with `<tool> is a\nKeycloak-only operation — authentik API v3 has no equivalent API. <hint>`.\n\n### authentik-only data\n\n`stale_access_audit` includes an `orphanedSessions` check that needs a\n**global** session list. Only authentik exposes one. On a **Keycloak** target\nthat check silently contributes nothing — `orphanedSessions` is always `[]` and\n`orphanedSessionCount` is always `0`. Do **not** report that as \"no orphaned\nsessions found\" on Keycloak; the check did not run. The other three findings in\nthat audit are unaffected.\n\n### Everything else works on both\n\n`identity_overview`, `realm_info`, `list_identity_providers`, `list_users`,\n`user_detail`, `user_count`, `user_sessions`, `user_credentials`, `list_groups`,\n`group_members`, `login_events`, `admin_events`, `list_clients`,\n`client_detail`, all four analyses, `disable_user`, `enable_user`,\n`revoke_user_sessions`, `update_client_redirect_uris`, `undo_list`,\n`undo_apply` — the normalized rows use the same field names on both platforms.\n\n## What still needs a prompt\n\nThese are model-behaviour problems the harness cannot fix from the outside.\nCopy this into your agent's system prompt:\n\n```text\nYou operate a Keycloak or authentik identity provider through the\nidentity-aiops MCP tools.\n\nTOOL USE\n- Before answering any question about the current identity environment, you\n  MUST call a tool. Never answer from memory or assumption.\n- Actually invoke the tool. Do not describe the call you would make, and do not\n  emit an example JSON response in place of calling it.\n- If a tool call fails, report the real error verbatim. Never fill the gap with\n  a plausible-sounding answer.\n- Some tools are Keycloak-only and return an error explaining that on\n  authentik. That is a correct answer about the platform, not a tool failure:\n  do not retry it, and follow the alternative the error names.\n\nREADING RESULTS\n- Read the whole result before concluding. Listings return \"returned\", \"limit\",\n  and \"truncated\". If \"truncated\" is true, say so and re-run with a higher\n  limit instead of treating the partial result as complete.\n- The analyses return \"inputsTruncated\" / \"feedTruncated\". When either is true,\n  every count is a lower bound — a threshold may have gone unreached only\n  because the events that would have reached it were never fetched. Never\n  report a clipped analysis as an all-clear.\n- A null field means the IdP did not return that value. Report it as \"not\n  available\" — never infer it. A null lastLogin is \"no sign-in on record\"; a\n  null passwordPolicy is \"the realm did not report one\", not \"no policy\".\n- Report values exactly as returned. Do not normalise, translate, or prettify\n  usernames, event types, error codes, or ids.\n\nIDENTIFIERS — do not confuse these\n- A user id (Keycloak UUID, authentik integer pk) is not a username. Tools take\n  the id; get it from list_users.\n- A client's internal id (what client_detail and the client writes take) is not\n  its clientId (the public OAuth identifier shown to end users). list_clients\n  returns both.\n- A group id is not a group name or path.\n- A realm is a Keycloak concept. authentik has no realms; its target's realm\n  field is a label only.\n\nSCOPE\n- Separate observation from interpretation. State what the tools returned, then\n  any interpretation, clearly marked as such.\n- Do not assert that an account is compromised, dormant, or misconfigured\n  unless a tool result supports it. These conclusions get people locked out.\n- Do not add generic identity-security advice that does not follow from the\n  tool output.\n```\n\n## Recommended setup for a local model\n\nStart with a connection that *cannot* write, verify, and widen the account's\npermission only when you trust the setup. Identity writes are unusually\nconsequential — `disable_user` and `revoke_user_sessions` lock a person out of\neverything behind the IdP.\n\n```bash\n# Give the Keycloak service account only view-* roles (or an authentik token\n# without manage scope). A write then fails at the server, not on a flag a\n# model can argue around. Then:\nidentity-aiops doctor\n```\n\nOptionally annotate the audit trail with who is operating and why — recorded on\nevery row, never required:\n\n```bash\nexport IDENTITY_AUDIT_APPROVED_BY=\"your.name@example.com\"\nexport IDENTITY_AUDIT_RATIONALE=\"access review 2026-07-20\"\n```\n\n## If your model still struggles\n\nSome behaviours are model-capacity limits rather than prompt problems:\n\n- **Multi-tool workflows time out or drift.** Prefer the four analysis tools —\n  `login_failure_rca`, `stale_access_audit`, `client_misconfig_audit`,\n  `mfa_coverage_analysis` do the multi-step correlation inside one call, so the\n  model does not have to chain reads and keep user ids straight.\n- **The model ignores later tool results in a long context.** Event feeds are\n  the worst offender: `login_events` with the default `max_results=200` is a\n  lot of rows. Filter with `event_type` and `user`, and lower `max_results` —\n  the `truncated` flag will tell you when you cut too deep.\n- **The model reports \"no data\" from a long feed.** Check `returned` in the\n  reply it received; if it is non-zero, the model dropped the payload rather\n  than the tool returning nothing. Ask a narrower question.\n- **The model retries a Keycloak-only tool on authentik.** Put the\n  platform-asymmetry paragraph from the system prompt above near the *top* of\n  your prompt, not the bottom.\n- **The model describes calls instead of making them.** This is usually a\n  runtime/tool-calling-format mismatch, not a prompt problem — check that your\n  client advertises the tools in the format your model was trained on.\n\nFeedback on running this with a specific local model is genuinely useful —\nopen an issue at\n[github.com/AIops-tools/Identity-AIops](https://github.com/AIops-tools/Identity-AIops/issues)\nwith the model, runtime, and what went wrong.\n\nFile v0.8.4:references/capabilities.md\n\n# identity-aiops capabilities\n\n> **29 MCP tools** (21 read, 6 write, 2 undo) across Keycloak (admin REST `/admin/realms/{realm}/...`,\n> client-credentials grant, refresh-on-401) and authentik (API v3 `/api/v3/...`,\n> Bearer token). The concrete REST paths below are modelled from each project's\n> public API and need live verification.\n\nA per-target `platform` field (`keycloak` / `authentik`) selects the API shape;\nthe same tool name resolves to the right path on each IdP via the platform\nregistry. Every substituted path segment (realm, user id, client id) is\npercent-encoded centrally.\n\n## Realm / system (read)\n\n| Tool | Keycloak path | authentik path | Returns |\n|------|---------------|----------------|---------|\n| `identity_overview` | (composite) | (composite) | platform/realm, user/client/IdP counts, failed-login feed size |\n| `realm_info` | `/admin/realms/{realm}` | `/api/v3/admin/system/` | brute-force protection, password/OTP policy (KC); version/environment (AK) |\n| `list_identity_providers` | `/admin/realms/{realm}/identity-provider/instances` | `/api/v3/sources/all/` | federated IdPs / sources with enabled state |\n\n## Users / groups (read)\n\n| Tool | Keycloak path | authentik path | Returns |\n|------|---------------|----------------|---------|\n| `list_users` | `/admin/realms/{realm}/users` | `/api/v3/core/users/` | normalized users (id, username, enabled, lastLogin, serviceAccount) |\n| `user_detail` | `/admin/realms/{realm}/users/{id}` | `/api/v3/core/users/{id}/` | one user incl. requiredActions/attributes |\n| `user_count` | `/admin/realms/{realm}/users/count` | `/api/v3/core/users/` (pagination.count) | total users — the doctor probe |\n| `user_sessions` | `/admin/realms/{realm}/users/{id}/sessions` | `/api/v3/core/authenticated_sessions/?user=` | active sessions (id, IP, start/last access) |\n| `user_credentials` | `/admin/realms/{realm}/users/{id}/credentials` | `/api/v3/authenticators/admin/all/?user=` | credentials/devices with second-factor flags |\n| `list_groups` | `/admin/realms/{realm}/groups` | `/api/v3/core/groups/` | groups |\n| `group_members` | `/admin/realms/{realm}/groups/{id}/members` | `/api/v3/core/groups/{id}/` (users_obj) | normalized member users |\n| `user_lockout_status` | `/admin/realms/{realm}/attack-detection/brute-force/users/{id}` | — (teaching error) | failure count, locked state, last failure IP |\n\n## Events (read)\n\n| Tool | Keycloak path | authentik path | Returns |\n|------|---------------|----------------|---------|\n| `login_events` | `/admin/realms/{realm}/events` | `/api/v3/events/events/` | normalized events {time, type, user, ip, client, error} |\n| `admin_events` | `/admin/realms/{realm}/admin-events` | `/api/v3/events/events/` (admin actions) | admin/config changes {operation, resource, actor, ip} |\n\n## Clients (read)\n\n| Tool | Keycloak path | authentik path | Returns |\n|------|---------------|----------------|---------|\n| `list_clients` | `/admin/realms/{realm}/clients` | `/api/v3/providers/oauth2/` | normalized clients (public flag, redirect URIs, flows, PKCE) |\n| `client_detail` | `/admin/realms/{realm}/clients/{id}` | `/api/v3/providers/oauth2/{id}/` | one client normalized |\n| `client_sessions` | `/admin/realms/{realm}/clients/{id}/user-sessions` | — (teaching error) | sessions on one client |\n| `client_session_stats` | `/admin/realms/{realm}/client-session-stats` | — (teaching error) | active-session counts per client |\n\n## Flagship analyses (read, pure heuristics over the reads)\n\n| Tool | Feed | Findings |\n|------|------|----------|\n| `login_failure_rca` | failed-login events (windowed) | password-spray (one IP → many users), targeted-brute-force (many IPs → one user), stale-stored-credential (one IP → one user), misconfigured-client (client-credential errors), expired-credential-storm, lockout-storm — each with counts, cause, action; thresholds included in output |\n| `stale_access_audit` | users + successful logins + sessions | staleUsers (idle > N days), neverLoggedIn, serviceAccountsInteractive, orphanedSessions |\n| `client_misconfig_audit` | normalized clients | wildcard-redirect-uri, http-redirect-uri (non-localhost), public-client-with-secret, implicit-flow-enabled, public-client-missing-pkce, password-grant-enabled — ranked riskScore (high=30/med=15/low=5) |\n| `mfa_coverage_analysis` | users + per-user credentials | coverage % overall/per group, usersWithoutMfa; second factors = otp/totp/hotp/webauthn/duo/sms (confirmed) |\n\n## Writes (governed: dry_run preview, audit, undo where reversible)\n\n| Tool | Risk | Keycloak call | authentik call | Undo |\n|------|:----:|---------------|----------------|------|\n| `disable_user` | med | `PUT users/{id}` `{enabled:false}` | `PATCH core/users/{id}/` `{is_active:false}` | `enable_user` (only if it was enabled) |\n| `enable_user` | **high** | `PUT users/{id}` `{enabled:true}` | `PATCH core/users/{id}/` `{is_active:true}` | `disable_user` (only if it was disabled) |\n| `revoke_user_sessions` | med | `POST users/{id}/logout` | `DELETE authenticated_sessions/{sid}/` each | none — priorState sessionCount |\n| `require_password_reset` | med | `PUT users/{id}` requiredActions ± UPDATE_PASSWORD | — (teaching error) | itself with `clear=True` (only if this call set it) |\n| `update_client_redirect_uris` | **high** | `PUT clients/{id}` `{redirectUris}` | `PATCH providers/oauth2/{id}/` `{redirect_uris}` | itself with the prior list |\n| `rotate_client_secret` | **high** | `GET`+`POST clients/{id}/client-secret` | — (teaching error) | none — priorState **masked** fingerprint |\n\nRisk-tier rationale: containment/hygiene actions an operator needs promptly\n(disable, revoke, require-reset) sit at medium; access-granting or\nboundary-replacing actions (enable, redirect-URI replace, secret rotation) sit\nat high. The tier is a descriptive label carried onto the audit row, not a\ngate — whether a write runs is the agent's judgement or the connecting\naccount's permissions.\n\nFile v0.8.4:references/cli-reference.md\n\n# identity-aiops CLI reference\n\nAll read commands print normalized JSON. All write commands take `--dry-run`\n(preview, no call, no audit) and otherwise require **double confirmation**;\nconfirmed writes execute through the governed MCP twins, so they land in\n`~/.identity-aiops/audit.db` with undo where applicable. `--target/-t` selects\na target from config (default: the first one).\n\n## Setup / health\n\n```bash\nidentity-aiops init                 # onboarding wizard (platform, base URL, realm, secret)\nidentity-aiops doctor               # config + secrets + token acquisition + user-count probe\nidentity-aiops doctor --skip-auth   # config/secrets checks only (no network)\nidentity-aiops overview             # one-shot estate summary\nidentity-aiops mcp                  # start the MCP server (stdio)\n```\n\n## Secrets (encrypted store)\n\n```bash\nidentity-aiops secret set <target>    # store/replace a secret (hidden prompt)\nidentity-aiops secret list            # target names only — never values\nidentity-aiops secret remove <target>\nidentity-aiops secret migrate         # legacy .env / env vars → secrets.enc\n```\n\nMaster password: `IDENTITY_AIOPS_MASTER_PASSWORD` (non-interactive/MCP) or an\ninteractive prompt on a TTY.\n\n## Events\n\n```bash\nidentity-aiops events                          # recent auth events\nidentity-aiops events --type LOGIN_ERROR -n 50 # Keycloak failed logins\nidentity-aiops events --type login_failed      # authentik failed logins\nidentity-aiops events --user alice\n```\n\n## Users\n\n```bash\nidentity-aiops users list [--search alice] [--limit 200]\nidentity-aiops users show <user-id>\nidentity-aiops users sessions <user-id>\nidentity-aiops users credentials <user-id>          # MFA surface\n\n# governed writes\nidentity-aiops users disable <user-id> [--dry-run]          # med, undo: enable\nidentity-aiops users enable <user-id> [--dry-run]           # HIGH\nidentity-aiops users revoke-sessions <user-id> [--dry-run]  # med, irreversible\nidentity-aiops users require-reset <user-id> [--clear] [--dry-run]\n```\n\n## Clients\n\n```bash\nidentity-aiops clients list [--limit 200]\nidentity-aiops clients show <client-id>\n\n# governed writes\nidentity-aiops clients set-redirect-uris <client-id> -u https://a/cb -u https://b/cb [--dry-run]  # HIGH\nidentity-aiops clients rotate-secret <client-id> [--dry-run]                                       # HIGH, masked\n```\n\n## Environment variables\n\n| Variable | Purpose |\n|----------|---------|\n| `IDENTITY_AIOPS_HOME` | relocate all state (config, secrets, audit, undo) |\n| `IDENTITY_AIOPS_CONFIG` | alternate config.yaml path (MCP server) |\n| `IDENTITY_AIOPS_MASTER_PASSWORD` | unlock secrets.enc non-interactively |\n| `IDENTITY_AUDIT_APPROVED_BY` / `IDENTITY_AUDIT_RATIONALE` | optional audit annotations (who/why), recorded when set |\n| `IDENTITY_MAX_TOOL_CALLS` / `IDENTITY_MAX_TOOL_SECONDS` | session budget ceilings |\n| `IDENTITY_<TARGET>_SECRET` | legacy plaintext secret fallback (deprecated) |\n\nFile v0.8.4:references/setup-guide.md\n\n# identity-aiops setup & security guide\n\n> Verification status: mock-validated; no recorded live IdP run yet. Both **Keycloak**\n> and **authentik** are free/self-hostable (each runs from a single container), so a lab is\n> the easiest live check. The modelled REST paths are the largest verification\n> debt.\n\n## 1. Install\n\n```bash\nuv tool install identity-aiops       # or: pipx install identity-aiops\n```\n\n## 2. What you need per IdP\n\n- **Keycloak** — a **confidential client** with *Client authentication* ON and\n  *Service accounts roles* enabled (Clients → Create client). Grant its service\n  account the `realm-management` roles the agent should have:\n  - reads/analyses only: `view-users`, `view-events`, `view-clients`,\n    `view-realm`, `view-identity-providers`\n  - governed writes too: add `manage-users` and/or `manage-clients`\n  identity-aiops exchanges the client's **client_id + secret** at\n  `/realms/{realm}/protocol/openid-connect/token` (client-credentials grant)\n  and refreshes the short-lived token automatically on a 401.\n- **authentik** — an **API token** (Directory → Tokens & App passwords) for a\n  least-privileged admin user. The token is sent as `Authorization: Bearer` on\n  every call.\n\n## 3. Onboard with the wizard\n\n```bash\nidentity-aiops init\n```\n\nThe wizard asks, per target, for the **platform** (`keycloak` / `authentik`),\nthe **base URL** (e.g. `https://sso.example.com`), TLS verification (default\n**ON**; answer No only for self-signed lab certs), and — Keycloak only — the\n**realm** (default `master`) and the **client_id** (saved as `username`). The\nsecret (client secret / API token) goes **encrypted** into\n`~/.identity-aiops/secrets.enc`; non-secret details go to\n`~/.identity-aiops/config.yaml`.\n\nExample `config.yaml`:\n\n```yaml\ntargets:\n  - name: sso1\n    platform: keycloak\n    base_url: https://sso.example.com\n    realm: master\n    username: identity-aiops-agent\n    verify_ssl: true\n  - name: ak1\n    platform: authentik\n    base_url: https://auth.example.com\n    verify_ssl: true\n```\n\n## 4. Verify\n\n```bash\nidentity-aiops doctor\n```\n\nDoctor checks the config, the encrypted store (and its permissions), then per\ntarget runs the full auth path (Keycloak token acquisition / authentik bearer)\nplus a cheap realm probe — the user count. Exit code 0 = healthy.\n\n## 5. MCP client configuration\n\n```json\n{\n  \"mcpServers\": {\n    \"identity-aiops\": {\n      \"command\": \"uvx\",\n      \"args\": [\"--from\", \"identity-aiops\", \"identity-aiops-mcp\"],\n      \"env\": {\n        \"IDENTITY_AIOPS_MASTER_PASSWORD\": \"<master password>\",\n        \"IDENTITY_AUDIT_APPROVED_BY\": \"<optional: attributed on audit rows>\"\n      }\n    }\n  }\n}\n```\n\nMCP clients start the server with a minimal environment — shell-profile\nvariables are NOT inherited; put everything the server needs in the `env`\nblock.\n\n## 6. Security notes\n\n- Secrets: Fernet-encrypted (scrypt-derived key), chmod 600, never plaintext;\n  legacy `IDENTITY_<TARGET>_SECRET` env fallback warns and should be migrated\n  (`identity-aiops secret migrate`).\n- Least privilege: scope the Keycloak service account / authentik token to the\n  roles you actually want the agent to exercise — the reads/analyses work with\n  view-only roles.\n- High-risk writes (`enable_user`, `update_client_redirect_uris`,\n  `rotate_client_secret`) are tagged risk=high on the audit row; whether they\n  run is the connecting account's permissions or your agent's judgement, not a\n  tool-side gate. `IDENTITY_AUDIT_APPROVED_BY` / `IDENTITY_AUDIT_RATIONALE` are\n  optional annotations recorded when set.\n- `rotate_client_secret` never shows a secret — fetch the new value from the\n  admin console over a trusted channel.\n- Audit/undo live in `~/.identity-aiops/` (`audit.db`, `undo.db`), relocatable\n  via `IDENTITY_AIOPS_HOME`.\n\nFile v0.8.4:skill-card.md\n\n## Description:\n\nIdentity-aiops helps agents inspect and operate Keycloak or authentik identity providers, including users, sessions, events, OAuth clients, MFA coverage, root-cause analyses, and governed write actions.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[zw008](https://clawhub.ai/user/zw008)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nIdentity and platform engineers use this skill to investigate Keycloak or authentik estates, triage login failures and stale access, audit OAuth client posture, measure MFA coverage, and perform approved identity operations.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The skill can perform high-impact identity-provider changes when the connected Keycloak or authentik account has write permissions.\n\nMitigation: Start with view-only credentials, grant manage-users or manage-clients only for approved work, and treat write tools as immediately actionable under the connected account's permissions.\n\nRisk: Approval environment variables are audit annotations rather than an enforcement gate.\n\nMitigation: Use identity-provider permissions and agent policy to control whether writes can run; do not rely on audit metadata fields to block execution.\n\nRisk: The external identity-aiops package may be fetched without a pinned or independently verified version.\n\nMitigation: Pin or otherwise verify the identity-aiops package version before installation or MCP server startup.\n\n## Reference(s):\n\n- [ClawHub skill page](https://clawhub.ai/zw008/skills/identity-aiops)\n- [Project homepage](https://github.com/AIops-tools/Identity-AIops)\n- [Capabilities reference](references/capabilities.md)\n- [CLI reference](references/cli-reference.md)\n- [Setup and security guide](references/setup-guide.md)\n- [Agent guardrails](references/agent-guardrails.md)\n\n## Skill Output:\n\n**Output Type(s):** [text, markdown, shell commands, configuration, guidance]\n\n**Output Format:** [Markdown, JSON tool results, and inline shell or configuration snippets]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Outputs may include identity-provider observations, heuristic analyses, dry-run write plans, and audit-oriented operational guidance.]\n\n## Skill Version(s):\n\n0.8.4 (source: server release evidence)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v0.8.3: 7 files, 19822 bytes\n\nFiles: references/agent-guardrails.md (10399b), references/capabilities.md (5977b), references/cli-reference.md (2965b), references/setup-guide.md (3798b), skill-card.md (2917b), SKILL.md (17809b), _meta.json (133b)\n\nFile v0.8.3:SKILL.md\n\n---\nname: identity-aiops\nslug: identity-aiops\ndisplayName: \"Identity AIops\"\nsummary: \"Governed Keycloak + authentik identity ops: users, events, clients, MFA, RCA. 29 tools.\"\nlicense: MIT\nhomepage: https://github.com/AIops-tools/Identity-AIops\ntags: [aiops, mcp, governance, identity]\ndescription: >\n  Use this skill whenever the user needs to operate a Keycloak or authentik identity provider — a one-shot overview, realm settings, users with sessions/credentials/groups/lockout status, authentication and admin events, OAuth/OIDC clients, four flagship RCAs (login-failure/lockout-storm, stale access, client misconfiguration, MFA coverage), and governed writes (disable/enable a user, revoke sessions, require a password reset, replace redirect URIs, rotate a client secret).\n  Always use this skill for \"Keycloak\", \"authentik\", \"realm\", \"SSO users\", \"login failures\", \"brute force logins\", \"locked out users\", \"stale accounts\", \"service account misuse\", \"redirect URI\", \"PKCE\", \"implicit flow\", \"client secret rotation\", \"MFA coverage\", \"who has no 2FA\" when the context is a Keycloak/authentik IdP.\n  Do NOT use when the target is something other than a Keycloak/authentik identity provider (a hypervisor, storage appliance, backup product, container-orchestration cluster, firewall, database, or OT/industrial equipment) — route those to the appropriate other AIops-tools skill. Cloud IdPs (Okta, Entra ID, Auth0) are out of scope.\n  Governed identity operations with a built-in governance harness (audit, policy, token budget, undo, risk-tiers).\ninstaller:\n  kind: uv\n  package: identity-aiops\nargument-hint: \"[a user/client id, a realm, or describe your identity task]\"\nallowed-tools:\n  - Bash\nmetadata: {\"openclaw\":{\"requires\":{\"anyBins\":[\"identity-aiops\",\"uvx\"]},\"optional\":{\"env\":[\"IDENTITY_AIOPS_CONFIG\",\"IDENTITY_AIOPS_MASTER_PASSWORD\"]},\"homepage\":\"https://github.com/AIops-tools/Identity-AIops\",\"emoji\":\"🔐\",\"os\":[\"macos\",\"linux\"]}}\ncompatibility: >\n  Standalone, self-governed identity-provider operations across Keycloak (admin REST API /admin/realms/{realm}/..., OAuth2 client-credentials grant against the realm token endpoint with automatic refresh-on-401) and authentik (API v3 /api/v3/..., long-lived API token as a Bearer header). Each target in the config names its own platform, and a name-keyed platform registry selects the API shape, so the same tools work on both and one config can span a mixed estate. The governance harness (audit, policy, token/runaway budget, undo, risk-tiers) is bundled in the package — no external skill-family dependency.\n  All write operations are audited to a local SQLite DB under ~/.identity-aiops/ (relocatable via IDENTITY_AIOPS_HOME).\n  Credentials: the Keycloak confidential client's client secret or the authentik API token is stored ENCRYPTED in ~/.identity-aiops/secrets.enc (Fernet/AES-128 + scrypt-derived key) — never plaintext on disk. Run 'identity-aiops init' to onboard (it asks for the platform, base URL, and — Keycloak — realm + client_id), or 'identity-aiops secret set <target>' to add one. The store is unlocked by a master password from IDENTITY_AIOPS_MASTER_PASSWORD (non-interactive/MCP/CI) or an interactive prompt (CLI on a TTY). A legacy plaintext env var IDENTITY_<TARGET_NAME_UPPER>_SECRET is still honoured as a fallback with a deprecation warning (migrate with 'identity-aiops secret migrate'). Secrets are held only in memory, never logged or echoed; rotate_client_secret returns and records masked fingerprints only.\n  State-changing operations pass through the @governed_tool decorator (budget guard + audit + risk-tier labelling). enable_user, update_client_redirect_uris, and rotate_client_secret are risk=high with dry_run; revoke_user_sessions and rotate_client_secret are irreversible (priorState only). Reversible writes (disable_user/enable_user, require_password_reset, update_client_redirect_uris) capture the real fetched before-state and record an inverse undo descriptor. The tool records every call but does not decide whether a write is permitted — that is the agent's judgement or the connecting account's permissions.\n  Webhooks: none — no outbound network calls beyond the configured Keycloak / authentik REST API.\n  SSL: verify_ssl defaults to ON; disable only for self-signed lab certs.\n  Transitive dependencies: httpx (HTTP client) and the MCP SDK. No post-install scripts or background services.\n  Verification status: mock-validated; no recorded end-to-end run against a live IdP yet, and the modelled REST paths are the largest verification debt. Both Keycloak and authentik are free/self-hostable (each runs from a single container), so a lab is the cheapest live check. See docs/VERIFICATION.md.\n---\n\n# Identity AIops\n\n> **Disclaimer**: Community-maintained open-source project, **not affiliated with, endorsed by, or sponsored by the Keycloak project, Red Hat, Authentik Security Inc., or the authentik project.** Keycloak and authentik are trademarks of their respective owners. Source at [github.com/AIops-tools/Identity-AIops](https://github.com/AIops-tools/Identity-AIops) under the MIT license.\n\nGoverned identity operations — **29 MCP tools** across **Keycloak** (admin REST\n`/admin/realms/{realm}/...`) and **authentik** (API v3 `/api/v3/...`), every one\nwrapped with the bundled `@governed_tool` harness: a local unified audit log\nunder `~/.identity-aiops/`, policy engine, token/runaway budget guard,\nundo-token recording, and risk-tier labelling on the audit row. A per-target\n`platform` field selects the API shape, so the same tools work on both IdPs and\none config can span a mixed estate. The Keycloak client secret / authentik API\ntoken is stored **encrypted** (`~/.identity-aiops/secrets.enc`, Fernet +\nscrypt) — never plaintext on disk.\n\n> **Standalone**: the governance harness is bundled in the package\n> (`identity_aiops.governance`) — no external skill-family dependency. Both\n> platforms are free/self-hostable, so a self-hosted lab is the cheapest live\n> check; verification status and the checklist are in `docs/VERIFICATION.md`.\n\n## What This Skill Does\n\n| Group | Tools | Count | R/W |\n|-------|-------|:-----:|:---:|\n| **Realm / system** | identity_overview, realm_info, list_identity_providers | 3 | read |\n| **Users / groups** | list_users, user_detail, user_count, user_sessions, user_credentials, list_groups, group_members, user_lockout_status | 8 | read |\n| **Events** | login_events, admin_events | 2 | read |\n| **Clients** | list_clients, client_detail, client_sessions, client_session_stats | 4 | read |\n| **Flagship analyses** | login_failure_rca, stale_access_audit, client_misconfig_audit, mfa_coverage_analysis | 4 | read |\n| **Writes** | disable_user, revoke_user_sessions, require_password_reset | 3 | write (med) |\n| **Writes** | enable_user, update_client_redirect_uris, rotate_client_secret | 3 | write (**high**) |\n| **Undo** | undo_list, undo_apply | 2 | read + replay |\n\nThe four flagship analyses are transparent heuristics that report their numbers,\nnever a black-box verdict: `login_failure_rca` windows the failed-auth feed by\nuser/IP/client and separates password spray, targeted brute-force, a stale\nstored credential, a misconfigured client, an expired-credential storm, and a\nlockout storm; `stale_access_audit` flags dormant and never-used accounts,\ninteractive service accounts, and orphaned sessions; `client_misconfig_audit`\nranks clients by OAuth-BCP risk (wildcard/http redirects, secrets in public\nclients, implicit flow, missing PKCE, password grant); `mfa_coverage_analysis`\nreports second-factor coverage overall and per group.\n\n## Quick Install\n\n```bash\nuv tool install identity-aiops\nidentity-aiops init       # wizard: pick platform (keycloak/authentik) + encrypted secret\nidentity-aiops doctor\n```\n\nOr as an OpenClaw plugin, which installs this skill and its MCP server together:\n\n```bash\nopenclaw plugins install clawhub:@zw008/identity-aiops\nopenclaw skills info identity-aiops          # expect: Visible to model: yes\n```\n\nNeeds `uvx` on `PATH`: the MCP server is fetched with uv, pinned to this release.\n\n## When to Use This Skill\n\n- Get a one-shot snapshot (`overview` / `realm_info` / `user_count`)\n- Triage a login-failure or lockout storm (`login_failure_rca`) → cause + action\n- Run an access re-certification (`stale_access_audit`: idle users,\n  never-logged-in accounts, service-account misuse, orphaned sessions)\n- Audit OAuth clients (`client_misconfig_audit`: redirect URIs, PKCE, implicit\n  flow, password grant) and fix them (`update_client_redirect_uris`)\n- Measure and close the MFA gap (`mfa_coverage_analysis`, `user_credentials`)\n- Contain a compromised account (`disable_user` + `revoke_user_sessions` +\n  `require_password_reset`, all governed; re-enable is tagged high risk)\n- Rotate a leaked client secret (`rotate_client_secret`, high risk, masked)\n\n**Do NOT use when** the target is not a Keycloak/authentik IdP — route\nhypervisor, storage, backup, cluster, network/firewall, database, endpoint, or\nOT/industrial work to the appropriate other AIops-tools skill. Cloud IdPs\n(Okta, Entra ID, Auth0) are out of scope.\n\n## Related Skills — Skill Routing\n\n| If the user wants… | Use |\n|--------------------|-----|\n| Keycloak / authentik identity ops | **identity-aiops** (this skill) |\n| A non-identity platform (hypervisor, storage, backup, cluster, network device/controller, firewall, database, containers, endpoints, local LLM governance, compliance evidence) | the appropriate **other AIops-tools** skill (proxmox-aiops, truenas-aiops, ceph-aiops, veeam-aiops, k8s-aiops, network-aiops, fabric-aiops, firewall-aiops, postgres-aiops, container-host-aiops, endpoint-aiops, ai-guardian, compliance-aiops, …) |\n| Cloud IdPs (Okta, Entra ID, Auth0) | out of scope for this tool |\n\n## Common Workflows\n\nEach recipe starts from a read or one of the four RCAs and ends in a governed\nwrite. The **RCAs are MCP tools** (`login_failure_rca`, `stale_access_audit`,\n`client_misconfig_audit`, `mfa_coverage_analysis`) — call them through the MCP\nserver; the CLI covers the reads and the writes. Every CLI write accepts\n`--dry-run` and otherwise double-confirms.\n\n### 1. \"We're being brute-forced — contain it\"\n\n1. `identity-aiops overview` → how big is the failed-login feed right now, and\n   is this one account or the whole realm?\n2. MCP `login_failure_rca` → findings ranked with numbers, separating password\n   **spray** from one IP, **targeted** brute-force on one account, a client\n   failing with credential errors (a rotated secret not deployed), an\n   expired-credential storm, and a lockout storm.\n3. `identity-aiops events --type LOGIN_ERROR --user <username> -n 200` → the\n   raw failures behind the finding (authentik: `--type login_failed`).\n4. `identity-aiops users show <user-id>` and `identity-aiops users sessions\n   <user-id>` → is the account already compromised, i.e. did any attempt\n   actually succeed?\n5. Contain: `identity-aiops users disable <user-id> --dry-run`, then for real\n   (reversible — the fetched before-state is captured and an `enable_user`\n   inverse recorded).\n6. `identity-aiops users revoke-sessions <user-id>` → kill live sessions.\n   **Irreversible** (priorState only) — disabling alone does not end sessions\n   already issued, so this step is what actually stops the attacker.\n7. `identity-aiops undo list` → confirm the disable is reversible before you\n   hand off.\n\n**Failure branch**: if the RCA classifies it as a **misconfigured client**\nrather than an attack (mass credential errors from one client id), do not\ndisable users — you would lock out legitimate people while the real fault is a\nrotated secret that was never deployed. Go to recipe 3. If you disabled the\nwrong account, `identity-aiops users enable <user-id>` is **high** risk and\nneeds `IDENTITY_AUDIT_APPROVED_BY` + `IDENTITY_AUDIT_RATIONALE`, deliberately —\nre-enabling reverses containment.\n\n### 2. \"Quarterly access re-certification\"\n\n1. MCP `stale_access_audit` (e.g. `stale_days=90`) → dormant users with day\n   counts, never-logged-in accounts, service accounts being used\n   interactively, and orphaned sessions.\n2. `identity-aiops users list --search <name>` / `identity-aiops users show\n   <user-id>` → confirm each candidate is genuinely the account you think.\n3. `identity-aiops users sessions <user-id>` → check for a live session before\n   you touch a \"dormant\" account.\n4. Confirm with the account owner or its manager. Then, per account:\n   `identity-aiops users disable <user-id>` (reversible, undo-recorded).\n5. `identity-aiops users revoke-sessions <user-id>` for the orphaned sessions\n   the audit found (irreversible).\n6. Re-run `stale_access_audit` to confirm the list shrank as expected.\n\n**Failure branch**: an **interactive service account** finding is not a\ndisable candidate — disabling it takes down whatever integration depends on\nit. Trace the client first (`identity-aiops clients show <client-id>`,\n`identity-aiops clients list`) and fix the integration to stop using\ninteractive login. If a disable breaks something unexpectedly,\n`identity-aiops undo apply <id>` replays the captured prior state.\n\n### 3. \"Harden the OAuth clients before the audit\"\n\n1. MCP `client_misconfig_audit` → per-client `riskScore` with the evidence\n   behind it: wildcard or plain-`http` redirect URIs, a public client holding\n   a secret, implicit flow enabled, missing PKCE, password grant allowed.\n2. `identity-aiops clients show <client-id>` → the full current client\n   configuration, so you replace the right values.\n3. `identity-aiops clients set-redirect-uris <client-id> --uri\n   https://app.example.com/callback --dry-run` → note that `--uri` is repeated\n   and supplies the **FULL new list**, replacing what is there.\n4. Re-run without `--dry-run`: **high** risk, double confirm, requires\n   `IDENTITY_AUDIT_APPROVED_BY` + `IDENTITY_AUDIT_RATIONALE`. The prior URI\n   list is captured, so undo replays it exactly.\n5. If a secret leaked: `identity-aiops clients rotate-secret <client-id>`\n   (**high** risk, **irreversible**, masked priorState) — then deploy the new\n   secret everywhere that client is used.\n6. Re-run `client_misconfig_audit` to confirm the score dropped.\n\n**Failure branch**: rotating a secret before the deployments are ready is how\nyou cause recipe 1's \"misconfigured client\" storm — every service using the old\nsecret starts failing authentication immediately, and rotation cannot be\nundone. Stage the deployment first. If a redirect-URI replacement breaks a\nlogin flow, `identity-aiops undo apply <id>` restores the exact prior list;\nthis is why the URI change is reversible and the rotation is not.\n\n### 4. \"Show me who still has no second factor\"\n\n1. MCP `mfa_coverage_analysis` → coverage percentage, the worst groups first,\n   and the per-user gap list.\n2. `identity-aiops users credentials <user-id>` → what a specific user\n   actually has configured, so you distinguish \"no MFA\" from \"an enrolled\n   factor the analysis could not see\".\n3. `identity-aiops overview` and realm settings → confirm the realm's\n   brute-force protection and OTP policy actually require what you think they\n   require.\n4. Where a forced re-enrolment is part of the rollout:\n   `identity-aiops users require-reset <user-id> --dry-run`, then for real\n   (reversible — undo clears the pending requirement).\n5. `identity-aiops undo list` → confirm each reset flag can be cleared if the\n   rollout stalls.\n\n**Failure branch**: if a user is blocked out by the reset requirement (no\nworking recovery path, or they cannot complete enrolment),\n`identity-aiops users require-reset <user-id> --clear` removes the pending\nrequirement, and `identity-aiops undo apply <id>` does the same from the\nrecorded token. Do not chase a 100% coverage number by forcing resets on\nservice accounts — they have no interactive user to complete the flow, and the\n`stale_access_audit` in recipe 2 is the right tool for those.\n\n## Governance & Safety\n\nThe skill delivers reads and writes and records them; it does **not** decide\nwhether a write is permitted. That is your agent's judgement, or the permission\nof the account you connect it with (a Keycloak service account or authentik\ntoken without `manage-*` scope — writes then fail at the server). There is no\nread-only switch, policy file, or approval gate.\n\n- **Audit is the guarantee, and it is not bypassable.** Every call — MCP and\n  CLI alike — lands an audit row in `~/.identity-aiops/audit.db` (relocatable\n  via `IDENTITY_AIOPS_HOME`): params, status, and the risk tier.\n- `IDENTITY_AUDIT_APPROVED_BY` / `IDENTITY_AUDIT_RATIONALE` are optional\n  annotations recorded on the row (who/why); they are never required and never\n  block.\n- **Risk tier** — a descriptive label on the audit row derived from\n  `risk_level` (`enable_user`, `update_client_redirect_uris`,\n  `rotate_client_secret` = high; `disable_user`, `revoke_user_sessions`,\n  `require_password_reset` = medium); it gates nothing. Writes support\n  `--dry-run` and double confirmation at the CLI.\n- Reversible writes capture the real fetched before-state and record an\n  inverse descriptor (disable↔enable, reset-flag→clear, redirect-URI list\n  replay). `revoke_user_sessions` and `rotate_client_secret` are irreversible\n  (priorState only; secrets recorded masked).\n\n## References\n\n- `references/capabilities.md` — full tool + platform + API-path reference\n- `references/cli-reference.md` — CLI command reference\n- `references/setup-guide.md` — onboarding, credentials, and connectivity\n- `references/agent-guardrails.md` — running with a smaller / local model: the\n  truncation and null-field contracts, the Keycloak-vs-authentik tool\n  asymmetry, and a system prompt\n\nFile v0.8.3:_meta.json\n\n{\n  \"ownerId\": \"kn7b067awq2s97bn3d7p5qfhw5827pxc\",\n  \"slug\": \"identity-aiops\",\n  \"version\": \"0.8.3\",\n  \"publishedAt\": 1789451979806\n}\n\nFile v0.8.3:references/agent-guardrails.md\n\n# Agent guardrails — running identity-aiops with a smaller / local model\n\nIf you drive these tools with a local model (Llama, Qwen, Mistral … via Goose,\nOllama, LM Studio, or any OpenAI-compatible runtime), you will get noticeably\nbetter results with a short system prompt. This page gives you one, and — more\nimportantly — tells you which guardrails you **no longer need to write**, because\nthe tool now enforces them itself.\n\nThe distinction matters. A guardrail in a prompt is a request. A guardrail in the\nharness is a guarantee. Anything below that we could move into the harness, we did.\n\n## Authorization is not this tool's job — decide it where it belongs\n\nWhether a write should happen is your decision, or the account's. The tool does\nnot gate it — there is no read-only switch and no approval prompt to configure.\nThe two right places to control read vs write:\n\n- **The account you connect with.** Give the Keycloak service account (or the\n  authentik token) only the roles you want the agent to have — `view-users` /\n  `view-events` / `view-clients` and no `manage-*`. A write then fails at the\n  server, which is the only place the permission actually lives — no skill-side\n  flag can be argued around by a model, but a revoked permission cannot be.\n- **Your agent's system prompt.** If you want an observe-only session, tell the\n  model not to call the write tools (they are clearly tagged `[WRITE]`).\n\nWhat the tool *does* guarantee is that you can always see what happened:\n\n## What the tool enforces — do not waste prompt budget on these\n\n| You might be tempted to prompt | Why you don't need to |\n|---|---|\n| \"Don't invent a value when a field is missing\" | A field the IdP did not return comes back as `null`, never as `\"\"`. Absent and empty are distinguishable in the payload — a `lastLogin` of `null` means \"no sign-in on record\", not \"signed in at an empty time\". |\n| \"Tell me if the output was cut off\" | Every listing returns `{\"users\": [...], \"returned\": N, \"limit\": L, \"truncated\": true/false}` (same shape for `events`, `groups`, `members`, `clients`, `sessions`, `identityProviders`). Truncation is measured — one extra row is fetched — not guessed from a length coincidence. |\n| \"Tell me if the analysis only saw part of the data\" | The four analyses echo `inputsTruncated` / `feedTruncated`, and `truncated` + `maxRows` when a finding list was capped. The `*Count` fields are always the full totals. |\n| \"Preserve the ordering / tell me what's most urgent\" | `client_misconfig_audit` ranks by `riskScore` with the severity weights in the payload; `login_failure_rca` sorts findings worst-first and every finding carries the numbers that tripped it. Priority is in the payload, not implied by list position. |\n| \"Confirm before anything destructive\" | Write CLI commands have `--dry-run` plus double confirmation. |\n| \"Log what you did\" | Every call is audited to `~/.identity-aiops/audit.db` regardless of what the model says it did. |\n\n## Platform asymmetry — a teaching error is an answer, not a failure\n\nidentity-aiops speaks to **two** identity providers through one tool set, and\nthey do not have the same APIs. Some tools exist only on one platform. When you\ncall one against the other platform, it returns a **teaching error** that names\nthe gap and points at the alternative.\n\n**That error is a definitive answer about the platform, not a broken tool.**\nDo not retry it, do not try a different argument, and do not report the tool as\nfailing. Switch approach, or tell the user the platform does not support it.\nThis is the single most common way a smaller model wastes a turn here.\n\n### Keycloak-only tools\n\nOn an **authentik** target these return `{\"error\": ...}`:\n\n| Tool | Why | What to do instead |\n|---|---|---|\n| `user_lockout_status` | authentik keeps no per-user brute-force lockout register | Use `login_failure_rca` over the failed-auth feed |\n| `client_sessions` | authentik has no per-provider session listing | Use `user_sessions` per user |\n| `client_session_stats` | authentik has no per-client session rollup | Use `user_sessions` per user, or `stale_access_audit` |\n| `require_password_reset` | authentik has no required-actions concept | Issue a recovery link from the authentik admin UI |\n| `rotate_client_secret` | authentik has no secret-rotation endpoint | Set a new client secret on the OAuth2 provider |\n\nThe two reads fail with `Resource '<name>' is not mapped for platform\n'authentik'. Mapped resources: ...`; the two writes fail with `<tool> is a\nKeycloak-only operation — authentik API v3 has no equivalent API. <hint>`.\n\n### authentik-only data\n\n`stale_access_audit` includes an `orphanedSessions` check that needs a\n**global** session list. Only authentik exposes one. On a **Keycloak** target\nthat check silently contributes nothing — `orphanedSessions` is always `[]` and\n`orphanedSessionCount` is always `0`. Do **not** report that as \"no orphaned\nsessions found\" on Keycloak; the check did not run. The other three findings in\nthat audit are unaffected.\n\n### Everything else works on both\n\n`identity_overview`, `realm_info`, `list_identity_providers`, `list_users`,\n`user_detail`, `user_count`, `user_sessions`, `user_credentials`, `list_groups`,\n`group_members`, `login_events`, `admin_events`, `list_clients`,\n`client_detail`, all four analyses, `disable_user`, `enable_user`,\n`revoke_user_sessions`, `update_client_redirect_uris`, `undo_list`,\n`undo_apply` — the normalized rows use the same field names on both platforms.\n\n## What still needs a prompt\n\nThese are model-behaviour problems the harness cannot fix from the outside.\nCopy this into your agent's system prompt:\n\n```text\nYou operate a Keycloak or authentik identity provider through the\nidentity-aiops MCP tools.\n\nTOOL USE\n- Before answering any question about the current identity environment, you\n  MUST call a tool. Never answer from memory or assumption.\n- Actually invoke the tool. Do not describe the call you would make, and do not\n  emit an example JSON response in place of calling it.\n- If a tool call fails, report the real error verbatim. Never fill the gap with\n  a plausible-sounding answer.\n- Some tools are Keycloak-only and return an error explaining that on\n  authentik. That is a correct answer about the platform, not a tool failure:\n  do not retry it, and follow the alternative the error names.\n\nREADING RESULTS\n- Read the whole result before concluding. Listings return \"returned\", \"limit\",\n  and \"truncated\". If \"truncated\" is true, say so and re-run with a higher\n  limit instead of treating the partial result as complete.\n- The analyses return \"inputsTruncated\" / \"feedTruncated\". When either is true,\n  every count is a lower bound — a threshold may have gone unreached only\n  because the events that would have reached it were never fetched. Never\n  report a clipped analysis as an all-clear.\n- A null field means the IdP did not return that value. Report it as \"not\n  available\" — never infer it. A null lastLogin is \"no sign-in on record\"; a\n  null passwordPolicy is \"the realm did not report one\", not \"no policy\".\n- Report values exactly as returned. Do not normalise, translate, or prettify\n  usernames, event types, error codes, or ids.\n\nIDENTIFIERS — do not confuse these\n- A user id (Keycloak UUID, authentik integer pk) is not a username. Tools take\n  the id; get it from list_users.\n- A client's internal id (what client_detail and the client writes take) is not\n  its clientId (the public OAuth identifier shown to end users). list_clients\n  returns both.\n- A group id is not a group name or path.\n- A realm is a Keycloak concept. authentik has no realms; its target's realm\n  field is a label only.\n\nSCOPE\n- Separate observation from interpretation. State what the tools returned, then\n  any interpretation, clearly marked as such.\n- Do not assert that an account is compromised, dormant, or misconfigured\n  unless a tool result supports it. These conclusions get people locked out.\n- Do not add generic identity-security advice that does not follow from the\n  tool output.\n```\n\n## Recommended setup for a local model\n\nStart with a connection that *cannot* write, verify, and widen the account's\npermission only when you trust the setup. Identity writes are unusually\nconsequential — `disable_user` and `revoke_user_sessions` lock a person out of\neverything behind the IdP.\n\n```bash\n# Give the Keycloak service account only view-* roles (or an authentik token\n# without manage scope). A write then fails at the server, not on a flag a\n# model can argue around. Then:\nidentity-aiops doctor\n```\n\nOptionally annotate the audit trail with who is operating and why — recorded on\nevery row, never required:\n\n```bash\nexport IDENTITY_AUDIT_APPROVED_BY=\"your.name@example.com\"\nexport IDENTITY_AUDIT_RATIONALE=\"access review 2026-07-20\"\n```\n\n## If your model still struggles\n\nSome behaviours are model-capacity limits rather than prompt problems:\n\n- **Multi-tool workflows time out or drift.** Prefer the four analysis tools —\n  `login_failure_rca`, `stale_access_audit`, `client_misconfig_audit`,\n  `mfa_coverage_analysis` do the multi-step correlation inside one call, so the\n  model does not have to chain reads and keep user ids straight.\n- **The model ignores later tool results in a long context.** Event feeds are\n  the worst offender: `login_events` with the default `max_results=200` is a\n  lot of rows. Filter with `event_type` and `user`, and lower `max_results` —\n  the `truncated` flag will tell you when you cut too deep.\n- **The model reports \"no data\" from a long feed.** Check `returned` in the\n  reply it received; if it is non-zero, the model dropped the payload rather\n  than the tool returning nothing. Ask a narrower question.\n- **The model retries a Keycloak-only tool on authentik.** Put the\n  platform-asymmetry paragraph from the system prompt above near the *top* of\n  your prompt, not the bottom.\n- **The model describes calls instead of making them.** This is usually a\n  runtime/tool-calling-format mismatch, not a prompt problem — check that your\n  client advertises the tools in the format your model was trained on.\n\nFeedback on running this with a specific local model is genuinely useful —\nopen an issue at\n[github.com/AIops-tools/Identity-AIops](https://github.com/AIops-tools/Identity-AIops/issues)\nwith the model, runtime, and what went wrong.\n\nFile v0.8.3:references/capabilities.md\n\n# identity-aiops capabilities\n\n> **29 MCP tools** (21 read, 6 write, 2 undo) across Keycloak (admin REST `/admin/realms/{realm}/...`,\n> client-credentials grant, refresh-on-401) and authentik (API v3 `/api/v3/...`,\n> Bearer token). The concrete REST paths below are modelled from each project's\n> public API and need live verification.\n\nA per-target `platform` field (`keycloak` / `authentik`) selects the API shape;\nthe same tool name resolves to the right path on each IdP via the platform\nregistry. Every substituted path segment (realm, user id, client id) is\npercent-encoded centrally.\n\n## Realm / system (read)\n\n| Tool | Keycloak path | authentik path | Returns |\n|------|---------------|----------------|---------|\n| `identity_overview` | (composite) | (composite) | platform/realm, user/client/IdP counts, failed-login feed size |\n| `realm_info` | `/admin/realms/{realm}` | `/api/v3/admin/system/` | brute-force protection, password/OTP policy (KC); version/environment (AK) |\n| `list_identity_providers` | `/admin/realms/{realm}/identity-provider/instances` | `/api/v3/sources/all/` | federated IdPs / sources with enabled state |\n\n## Users / groups (read)\n\n| Tool | Keycloak path | authentik path | Returns |\n|------|---------------|----------------|---------|\n| `list_users` | `/admin/realms/{realm}/users` | `/api/v3/core/users/` | normalized users (id, username, enabled, lastLogin, serviceAccount) |\n| `user_detail` | `/admin/realms/{realm}/users/{id}` | `/api/v3/core/users/{id}/` | one user incl. requiredActions/attributes |\n| `user_count` | `/admin/realms/{realm}/users/count` | `/api/v3/core/users/` (pagination.count) | total users — the doctor probe |\n| `user_sessions` | `/admin/realms/{realm}/users/{id}/sessions` | `/api/v3/core/authenticated_sessions/?user=` | active sessions (id, IP, start/last access) |\n| `user_credentials` | `/admin/realms/{realm}/users/{id}/credentials` | `/api/v3/authenticators/admin/all/?user=` | credentials/devices with second-factor flags |\n| `list_groups` | `/admin/realms/{realm}/groups` | `/api/v3/core/groups/` | groups |\n| `group_members` | `/admin/realms/{realm}/groups/{id}/members` | `/api/v3/core/groups/{id}/` (users_obj) | normalized member users |\n| `user_lockout_status` | `/admin/realms/{realm}/attack-detection/brute-force/users/{id}` | — (teaching error) | failure count, locked state, last failure IP |\n\n## Events (read)\n\n| Tool | Keycloak path | authentik path | Returns |\n|------|---------------|----------------|---------|\n| `login_events` | `/admin/realms/{realm}/events` | `/api/v3/events/events/` | normalized events {time, type, user, ip, client, error} |\n| `admin_events` | `/admin/realms/{realm}/admin-events` | `/api/v3/events/events/` (admin actions) | admin/config changes {operation, resource, actor, ip} |\n\n## Clients (read)\n\n| Tool | Keycloak path | authentik path | Returns |\n|------|---------------|----------------|---------|\n| `list_clients` | `/admin/realms/{realm}/clients` | `/api/v3/providers/oauth2/` | normalized clients (public flag, redirect URIs, flows, PKCE) |\n| `client_detail` | `/admin/realms/{realm}/clients/{id}` | `/api/v3/providers/oauth2/{id}/` | one client normalized |\n| `client_sessions` | `/admin/realms/{realm}/clients/{id}/user-sessions` | — (teaching error) | sessions on one client |\n| `client_session_stats` | `/admin/realms/{realm}/client-session-stats` | — (teaching error) | active-session counts per client |\n\n## Flagship analyses (read, pure heuristics over the reads)\n\n| Tool | Feed | Findings |\n|------|------|----------|\n| `login_failure_rca` | failed-login events (windowed) | password-spray (one IP → many users), targeted-brute-force (many IPs → one user), stale-stored-credential (one IP → one user), misconfigured-client (client-credential errors), expired-credential-storm, lockout-storm — each with counts, cause, action; thresholds included in output |\n| `stale_access_audit` | users + successful logins + sessions | staleUsers (idle > N days), neverLoggedIn, serviceAccountsInteractive, orphanedSessions |\n| `client_misconfig_audit` | normalized clients | wildcard-redirect-uri, http-redirect-uri (non-localhost), public-client-with-secret, implicit-flow-enabled, public-client-missing-pkce, password-grant-enabled — ranked riskScore (high=30/med=15/low=5) |\n| `mfa_coverage_analysis` | users + per-user credentials | coverage % overall/per group, usersWithoutMfa; second factors = otp/totp/hotp/webauthn/duo/sms (confirmed) |\n\n## Writes (governed: dry_run preview, audit, undo where reversible)\n\n| Tool | Risk | Keycloak call | authentik call | Undo |\n|------|:----:|---------------|----------------|------|\n| `disable_user` | med | `PUT users/{id}` `{enabled:false}` | `PATCH core/users/{id}/` `{is_active:false}` | `enable_user` (only if it was enabled) |\n| `enable_user` | **high** | `PUT users/{id}` `{enabled:true}` | `PATCH core/users/{id}/` `{is_active:true}` | `disable_user` (only if it was disabled) |\n| `revoke_user_sessions` | med | `POST users/{id}/logout` | `DELETE authenticated_sessions/{sid}/` each | none — priorState sessionCount |\n| `require_password_reset` | med | `PUT users/{id}` requiredActions ± UPDATE_PASSWORD | — (teaching error) | itself with `clear=True` (only if this call set it) |\n| `update_client_redirect_uris` | **high** | `PUT clients/{id}` `{redirectUris}` | `PATCH providers/oauth2/{id}/` `{redirect_uris}` | itself with the prior list |\n| `rotate_client_secret` | **high** | `GET`+`POST clients/{id}/client-secret` | — (teaching error) | none — priorState **masked** fingerprint |\n\nRisk-tier rationale: containment/hygiene actions an operator needs promptly\n(disable, revoke, require-reset) sit at medium; access-granting or\nboundary-replacing actions (enable, redirect-URI replace, secret rotation) sit\nat high. The tier is a descriptive label carried onto the audit row, not a\ngate — whether a write runs is the agent's judgement or the connecting\naccount's permissions.\n\nFile v0.8.3:references/cli-reference.md\n\n# identity-aiops CLI reference\n\nAll read commands print normalized JSON. All write commands take `--dry-run`\n(preview, no call, no audit) and otherwise require **double confirmation**;\nconfirmed writes execute through the governed MCP twins, so they land in\n`~/.identity-aiops/audit.db` with undo where applicable. `--target/-t` selects\na target from config (default: the first one).\n\n## Setup / health\n\n```bash\nidentity-aiops init                 # onboarding wizard (platform, base URL, realm, secret)\nidentity-aiops doctor               # config + secrets + token acquisition + user-count probe\nidentity-aiops doctor --skip-auth   # config/secrets checks only (no network)\nidentity-aiops overview             # one-shot estate summary\nidentity-aiops mcp                  # start the MCP server (stdio)\n```\n\n## Secrets (encrypted store)\n\n```bash\nidentity-aiops secret set <target>    # store/replace a secret (hidden prompt)\nidentity-aiops secret list            # target names only — never values\nidentity-aiops secret remove <target>\nidentity-aiops secret migrate         # legacy .env / env vars → secrets.enc\n```\n\nMaster password: `IDENTITY_AIOPS_MASTER_PASSWORD` (non-interactive/MCP) or an\ninteractive prompt on a TTY.\n\n## Events\n\n```bash\nidentity-aiops events                          # recent auth events\nidentity-aiops events --type LOGIN_ERROR -n 50 # Keycloak failed logins\nidentity-aiops events --type login_failed      # authentik failed logins\nidentity-aiops events --user alice\n```\n\n## Users\n\n```bash\nidentity-aiops users list [--search alice] [--limit 200]\nidentity-aiops users show <user-id>\nidentity-aiops users sessions <user-id>\nidentity-aiops users credentials <user-id>          # MFA surface\n\n# governed writes\nidentity-aiops users disable <user-id> [--dry-run]          # med, undo: enable\nidentity-aiops users enable <user-id> [--dry-run]           # HIGH\nidentity-aiops users revoke-sessions <user-id> [--dry-run]  # med, irreversible\nidentity-aiops users require-reset <user-id> [--clear] [--dry-run]\n```\n\n## Clients\n\n```bash\nidentity-aiops clients list [--limit 200]\nidentity-aiops clients show <client-id>\n\n# governed writes\nidentity-aiops clients set-redirect-uris <client-id> -u https://a/cb -u https://b/cb [--dry-run]  # HIGH\nidentity-aiops clients rotate-secret <client-id> [--dry-run]                                       # HIGH, masked\n```\n\n## Environment variables\n\n| Variable | Purpose |\n|----------|---------|\n| `IDENTITY_AIOPS_HOME` | relocate all state (config, secrets, audit, undo) |\n| `IDENTITY_AIOPS_CONFIG` | alternate config.yaml path (MCP server) |\n| `IDENTITY_AIOPS_MASTER_PASSWORD` | unlock secrets.enc non-interactively |\n| `IDENTITY_AUDIT_APPROVED_BY` / `IDENTITY_AUDIT_RATIONALE` | optional audit annotations (who/why), recorded when set |\n| `IDENTITY_MAX_TOOL_CALLS` / `IDENTITY_MAX_TOOL_SECONDS` | session budget ceilings |\n| `IDENTITY_<TARGET>_SECRET` | legacy plaintext secret fallback (deprecated) |\n\nFile v0.8.3:references/setup-guide.md\n\n# identity-aiops setup & security guide\n\n> Verification status: mock-validated; no recorded live IdP run yet. Both **Keycloak**\n> and **authentik** are free/self-hostable (each runs from a single container), so a lab is\n> the easiest live check. The modelled REST paths are the largest verification\n> debt.\n\n## 1. Install\n\n```bash\nuv tool install identity-aiops       # or: pipx install identity-aiops\n```\n\n## 2. What you need per IdP\n\n- **Keycloak** — a **confidential client** with *Client authentication* ON and\n  *Service accounts roles* enabled (Clients → Create client). Grant its service\n  account the `realm-management` roles the agent should have:\n  - reads/analyses only: `view-users`, `view-events`, `view-clients`,\n    `view-realm`, `view-identity-providers`\n  - governed writes too: add `manage-users` and/or `manage-clients`\n  identity-aiops exchanges the client's **client_id + secret** at\n  `/realms/{realm}/protocol/openid-connect/token` (client-credentials grant)\n  and refreshes the short-lived token automatically on a 401.\n- **authentik** — an **API token** (Directory → Tokens & App passwords) for a\n  least-privileged admin user. The token is sent as `Authorization: Bearer` on\n  every call.\n\n## 3. Onboard with the wizard\n\n```bash\nidentity-aiops init\n```\n\nThe wizard asks, per target, for the **platform** (`keycloak` / `authentik`),\nthe **base URL** (e.g. `https://sso.example.com`), TLS verification (default\n**ON**; answer No only for self-signed lab certs), and — Keycloak only — the\n**realm** (default `master`) and the **client_id** (saved as `username`). The\nsecret (client secret / API token) goes **encrypted** into\n`~/.identity-aiops/secrets.enc`; non-secret details go to\n`~/.identity-aiops/config.yaml`.\n\nExample `config.yaml`:\n\n```yaml\ntargets:\n  - name: sso1\n    platform: keycloak\n    base_url: https://sso.example.com\n    realm: master\n    username: identity-aiops-agent\n    verify_ssl: true\n  - name: ak1\n    platform: authentik\n    base_url: https://auth.example.com\n    verify_ssl: true\n```\n\n## 4. Verify\n\n```bash\nidentity-aiops doctor\n```\n\nDoctor checks the config, the encrypted store (and its permissions), then per\ntarget runs the full auth path (Keycloak token acquisition / authentik bearer)\nplus a cheap realm probe — the user count. Exit code 0 = healthy.\n\n## 5. MCP client configuration\n\n```json\n{\n  \"mcpServers\": {\n    \"identity-aiops\": {\n      \"command\": \"uvx\",\n      \"args\": [\"--from\", \"identity-aiops\", \"identity-aiops-mcp\"],\n      \"env\": {\n        \"IDENTITY_AIOPS_MASTER_PASSWORD\": \"<master password>\",\n        \"IDENTITY_AUDIT_APPROVED_BY\": \"<optional: attributed on audit rows>\"\n      }\n    }\n  }\n}\n```\n\nMCP clients start the server with a minimal environment — shell-profile\nvariables are NOT inherited; put everything the server needs in the `env`\nblock.\n\n## 6. Security notes\n\n- Secrets: Fernet-encrypted (scrypt-derived key), chmod 600, never plaintext;\n  legacy `IDENTITY_<TARGET>_SECRET` env fallback warns and should be migrated\n  (`identity-aiops secret migrate`).\n- Least privilege: scope the Keycloak service account / authentik token to the\n  roles you actually want the agent to exercise — the reads/analyses work with\n  view-only roles.\n- High-risk writes (`enable_user`, `update_client_redirect_uris`,\n  `rotate_client_secret`) are tagged risk=high on the audit row; whether they\n  run is the connecting account's permissions or your agent's judgement, not a\n  tool-side gate. `IDENTITY_AUDIT_APPROVED_BY` / `IDENTITY_AUDIT_RATIONALE` are\n  optional annotations recorded when set.\n- `rotate_client_secret` never shows a secret — fetch the new value from the\n  admin console over a trusted channel.\n- Audit/undo live in `~/.identity-aiops/` (`audit.db`, `undo.db`), relocatable\n  via `IDENTITY_AIOPS_HOME`.\n\nFile v0.8.3:skill-card.md\n\n## Description:\n\nIdentity AIops helps agents operate Keycloak and authentik identity providers, including users, sessions, events, clients, MFA coverage, root-cause analyses, and governed identity writes.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[zw008](https://clawhub.ai/user/zw008)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nIdentity, platform, and security engineers use this skill to inspect and operate Keycloak or authentik estates, triage login and access issues, audit OAuth client and MFA posture, and perform selected governed remediation tasks.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The skill can perform high-impact identity administration changes such as disabling users, revoking sessions, changing redirect URIs, and rotating client secrets.\n\nMitigation: Start with view-only Keycloak or authentik credentials, grant manage roles only for approved workflows, and use dry-run previews where available.\n\nRisk: Server evidence reports unavailable provenance for this version and warns about use through an external package.\n\nMitigation: Review package provenance manually and pin the exact identity-aiops version intended for deployment.\n\nRisk: Identity credentials, the master password, and local audit or undo state are sensitive operational data.\n\nMitigation: Protect IDENTITY_AIOPS_MASTER_PASSWORD and the ~/.identity-aiops directory, and migrate legacy plaintext secret environment variables before production use.\n\nRisk: Approval metadata and risk labels are records, not enforcement gates.\n\nMitigation: Enforce authorization through least-privileged identity-provider accounts and agent policy rather than relying on the skill's recorded labels.\n\n## Reference(s):\n\n- [ClawHub skill page](https://clawhub.ai/zw008/skills/identity-aiops)\n- [Project homepage](https://github.com/AIops-tools/Identity-AIops)\n- [Capabilities reference](references/capabilities.md)\n- [Setup and security guide](references/setup-guide.md)\n- [CLI reference](references/cli-reference.md)\n- [Agent guardrails](references/agent-guardrails.md)\n\n## Skill Output:\n\n**Output Type(s):** [text, markdown, shell commands, configuration, guidance]\n\n**Output Format:** [Markdown and text guidance with inline shell commands, JSON-like tool results, and configuration snippets.]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Outputs may include normalized identity-provider data, truncation indicators, audit context, dry-run previews, undo references, and risk labels when supported by the tool.]\n\n## Skill Version(s):\n\n0.8.3 (source: server release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v0.8.2: 7 files, 19800 bytes\n\nFiles: references/agent-guardrails.md (10399b), references/capabilities.md (5977b), references/cli-reference.md (2965b), references/setup-guide.md (3798b), skill-card.md (3024b), SKILL.md (17809b), _meta.json (133b)\n\nFile v0.8.2:SKILL.md\n\n---\nname: identity-aiops\nslug: identity-aiops\ndisplayName: \"Identity AIops\"\nsummary: \"Governed Keycloak + authentik identity ops: users, events, clients, MFA, RCA. 29 tools.\"\nlicense: MIT\nhomepage: https://github.com/AIops-tools/Identity-AIops\ntags: [aiops, mcp, governance, identity]\ndescription: >\n  Use this skill whenever the user needs to operate a Keycloak or authentik identity provider — a one-shot overview, realm settings, users with sessions/credentials/groups/lockout status, authentication and admin events, OAuth/OIDC clients, four flagship RCAs (login-failure/lockout-storm, stale access, client misconfiguration, MFA coverage), and governed writes (disable/enable a user, revoke sessions, require a password reset, replace redirect URIs, rotate a client secret).\n  Always use this skill for \"Keycloak\", \"authentik\", \"realm\", \"SSO users\", \"login failures\", \"brute force logins\", \"locked out users\", \"stale accounts\", \"service account misuse\", \"redirect URI\", \"PKCE\", \"implicit flow\", \"client secret rotation\", \"MFA coverage\", \"who has no 2FA\" when the context is a Keycloak/authentik IdP.\n  Do NOT use when the target is something other than a Keycloak/authentik identity provider (a hypervisor, storage appliance, backup product, container-orchestration cluster, firewall, database, or OT/industrial equipment) — route those to the appropriate other AIops-tools skill. Cloud IdPs (Okta, Entra ID, Auth0) are out of scope.\n  Governed identity operations with a built-in governance harness (audit, policy, token budget, undo, risk-tiers).\ninstaller:\n  kind: uv\n  package: identity-aiops\nargument-hint: \"[a user/client id, a realm, or describe your identity task]\"\nallowed-tools:\n  - Bash\nmetadata: {\"openclaw\":{\"requires\":{\"anyBins\":[\"identity-aiops\",\"uvx\"]},\"optional\":{\"env\":[\"IDENTITY_AIOPS_CONFIG\",\"IDENTITY_AIOPS_MASTER_PASSWORD\"]},\"homepage\":\"https://github.com/AIops-tools/Identity-AIops\",\"emoji\":\"🔐\",\"os\":[\"macos\",\"linux\"]}}\ncompatibility: >\n  Standalone, self-governed identity-provider operations across Keycloak (admin REST API /admin/realms/{realm}/..., OAuth2 client-credentials grant against the realm token endpoint with automatic refresh-on-401) and authentik (API v3 /api/v3/..., long-lived API token as a Bearer header). Each target in the config names its own platform, and a name-keyed platform registry selects the API shape, so the same tools work on both and one config can span a mixed estate. The governance harness (audit, policy, token/runaway budget, undo, risk-tiers) is bundled in the package — no external skill-family dependency.\n  All write operations are audited to a local SQLite DB under ~/.identity-aiops/ (relocatable via IDENTITY_AIOPS_HOME).\n  Credentials: the Keycloak confidential client's client secret or the authentik API token is stored ENCRYPTED in ~/.identity-aiops/secrets.enc (Fernet/AES-128 + scrypt-derived key) — never plaintext on disk. Run 'identity-aiops init' to onboard (it asks for the platform, base URL, and — Keycloak — realm + client_id), or 'identity-aiops secret set <target>' to add one. The store is unlocked by a master password from IDENTITY_AIOPS_MASTER_PASSWORD (non-interactive/MCP/CI) or an interactive prompt (CLI on a TTY). A legacy plaintext env var IDENTITY_<TARGET_NAME_UPPER>_SECRET is still honoured as a fallback with a deprecation warning (migrate with 'identity-aiops secret migrate'). Secrets are held only in memory, never logged or echoed; rotate_client_secret returns and records masked fingerprints only.\n  State-changing operations pass through the @governed_tool decorator (budget guard + audit + risk-tier labelling). enable_user, update_client_redirect_uris, and rotate_client_secret are risk=high with dry_run; revoke_user_sessions and rotate_client_secret are irreversible (priorState only). Reversible writes (disable_user/enable_user, require_password_reset, update_client_redirect_uris) capture the real fetched before-state and record an inverse undo descriptor. The tool records every call but does not decide whether a write is permitted — that is the agent's judgement or the connecting account's permissions.\n  Webhooks: none — no outbound network calls beyond the configured Keycloak / authentik REST API.\n  SSL: verify_ssl defaults to ON; disable only for self-signed lab certs.\n  Transitive dependencies: httpx (HTTP client) and the MCP SDK. No post-install scripts or background services.\n  Verification status: mock-validated; no recorded end-to-end run against a live IdP yet, and the modelled REST paths are the largest verification debt. Both Keycloak and authentik are free/self-hostable (each runs from a single container), so a lab is the cheapest live check. See docs/VERIFICATION.md.\n---\n\n# Identity AIops\n\n> **Disclaimer**: Community-maintained open-source project, **not affiliated with, endorsed by, or sponsored by the Keycloak project, Red Hat, Authentik Security Inc., or the authentik project.** Keycloak and authentik are trademarks of their respective owners. Source at [github.com/AIops-tools/Identity-AIops](https://github.com/AIops-tools/Identity-AIops) under the MIT license.\n\nGoverned identity operations — **29 MCP tools** across **Keycloak** (admin REST\n`/admin/realms/{realm}/...`) and **authentik** (API v3 `/api/v3/...`), every one\nwrapped with the bundled `@governed_tool` harness: a local unified audit log\nunder `~/.identity-aiops/`, policy engine, token/runaway budget guard,\nundo-token recording, and risk-tier labelling on the audit row. A per-target\n`platform` field selects the API shape, so the same tools work on both IdPs and\none config can span a mixed estate. The Keycloak client secret / authentik API\ntoken is stored **encrypted** (`~/.identity-aiops/secrets.enc`, Fernet +\nscrypt) — never plaintext on disk.\n\n> **Standalone**: the governance harness is bundled in the package\n> (`identity_aiops.governance`) — no external skill-family dependency. Both\n> platforms are free/self-hostable, so a self-hosted lab is the cheapest live\n> check; verification status and the checklist are in `docs/VERIFICATION.md`.\n\n## What This Skill Does\n\n| Group | Tools | Count | R/W |\n|-------|-------|:-----:|:---:|\n| **Realm / system** | identity_overview, realm_info, list_identity_providers | 3 | read |\n| **Users / groups** | list_users, user_detail, user_count, user_sessions, user_credentials, list_groups, group_members, user_lockout_status | 8 | read |\n| **Events** | login_events, admin_events | 2 | read |\n| **Clients** | list_clients, client_detail, client_sessions, client_session_stats | 4 | read |\n| **Flagship analyses** | login_failure_rca, stale_access_audit, client_misconfig_audit, mfa_coverage_analysis | 4 | read |\n| **Writes** | disable_user, revoke_user_sessions, require_password_reset | 3 | write (med) |\n| **Writes** | enable_user, update_client_redirect_uris, rotate_client_secret | 3 | write (**high**) |\n| **Undo** | undo_list, undo_apply | 2 | read + replay |\n\nThe four flagship analyses are transparent heuristics that report their numbers,\nnever a black-box verdict: `login_failure_rca` windows the failed-auth feed by\nuser/IP/client and separates password spray, targeted brute-force, a stale\nstored credential, a misconfigured client, an expired-credential storm, and a\nlockout storm; `stale_access_audit` flags dormant and never-used accounts,\ninteractive service accounts, and orphaned sessions; `client_misconfig_audit`\nranks clients by OAuth-BCP risk (wildcard/http redirects, secrets in public\nclients, implicit flow, missing PKCE, password grant); `mfa_coverage_analysis`\nreports second-factor coverage overall and per group.\n\n## Quick Install\n\n```bash\nuv tool install identity-aiops\nidentity-aiops init       # wizard: pick platform (keycloak/authentik) + encrypted secret\nidentity-aiops doctor\n```\n\nOr as an OpenClaw plugin, which installs this skill and its MCP server together:\n\n```bash\nopenclaw plugins install clawhub:@zw008/identity-aiops\nopenclaw skil\n\nArchive v0.8.1: 7 files, 19723 bytes\n\nFiles: references/agent-guardrails.md (10399b), references/capabilities.md (5977b), references/cli-reference.md (2965b), references/setup-guide.md (3798b), skill-card.md (2811b), SKILL.md (17815b), _meta.json (133b)\n\nArchive v0.8.0: 7 files, 19640 bytes\n\nFiles: references/agent-guardrails.md (10399b), references/capabilities.md (5977b), references/cli-reference.md (2965b), references/setup-guide.md (3798b), skill-card.md (2848b), SKILL.md (17499b), _meta.json (133b)\n\nArchive v0.7.0: 7 files, 19647 bytes\n\nFiles: references/agent-guardrails.md (10399b), references/capabilities.md (5977b), references/cli-reference.md (2965b), references/setup-guide.md (3798b), skill-card.md (2900b), SKILL.md (17610b), _meta.json (133b)\n\nArchive v0.6.0: 7 files, 19708 bytes\n\nFiles: references/agent-guardrails.md (10399b), references/capabilities.md (5977b), references/cli-reference.md (2965b), references/setup-guide.md (3798b), skill-card.md (3026b), SKILL.md (17610b), _meta.json (133b)\n\nArchive v0.5.0: 7 files, 19698 bytes\n\nFiles: references/agent-guardrails.md (10399b), references/capabilities.md (5977b), references/cli-reference.md (2965b), references/setup-guide.md (3798b), skill-card.md (3015b), SKILL.md (17610b), _meta.json (133b)\n\nArchive v0.4.0: 7 files, 19583 bytes\n\nFiles: references/agent-guardrails.md (10399b), references/capabilities.md (5977b), references/cli-reference.md (2965b), references/setup-guide.md (3798b), skill-card.md (2830b), SKILL.md (17610b), _meta.json (133b)","readmeExcerpt":"Skill: identity-aiops Owner: zw008 Summary: Use this skill whenever the user needs to operate a Keycloak or authentik identity provider — a one-shot overview, realm settings, users with sessions/credentials/groups/lockout status, authentication and admin events, OAuth/OIDC clients, four flagship RCAs (login-failure/lockout-storm, stale access, client misconfiguration, MFA coverage), and governed writes (disable/enabl","codeSnippets":[],"executableExamples":[{"language":"bash","snippet":"uv tool install identity-aiops\nidentity-aiops init       # wizard: pick platform (keycloak/authentik) + encrypted secret\nidentity-aiops doctor"},{"language":"bash","snippet":"openclaw plugins install clawhub:@zw008/identity-aiops\nopenclaw skills info identity-aiops          # expect: Visible to model: yes"},{"language":"text","snippet":"You operate a Keycloak or authentik identity provider through the\nidentity-aiops MCP tools.\n\nTOOL USE\n- Before answering any question about the current identity environment, you\n  MUST call a tool. Never answer from memory or assumption.\n- Actually invoke the tool. Do not describe the call you would make, and do not\n  emit an example JSON response in place of calling it.\n- If a tool call fails, report the real error verbatim. Never fill the gap with\n  a plausible-sounding answer.\n- Some tools are Keycloak-only and return an error explaining that on\n  authentik. That is a correct answer about the platform, not a tool failure:\n  do not retry it, and follow the alternative the error names.\n\nREADING RESULTS\n- Read the whole result before concluding. Listings return \"returned\", \"limit\",\n  and \"truncated\". If \"truncated\" is true, say so and re-run with a higher\n  limit instead of treating the partial result as complete.\n- `login_failure_rca` findings are not ranked on one comparable quantity and carry no rank.\n  Weigh each finding's own counts and say which one you acted on; never treat the first as\n  the headline.\n- The analyses return \"inputsTruncated\" / \"feedTruncated\". When either is true,\n  every count is a lower bound — a threshold may have gone unreached only\n  because the events that would have reached it were never fetched. Never\n  report a clipped analysis as an all-clear.\n- A null field means the IdP did not return that value. Report it as \"not\n  available\" — never infer it. A null lastLogin is \"no sign-in on record\"; a\n  null passwordPolicy is \"the realm did not report one\", not \"no policy\".\n- Report values exactly as returned. Do not normalise, translate, or prettify\n  usernames, event types, error codes, or ids.\n\nIDENTIFIERS — do not confuse these\n- A user id (Keycloak UUID, authentik integer pk) is not a username. Tools take\n  the id; get it from list_users.\n- A client's internal id (what client_detail and the client writes take) is not\n  its clientId (the "},{"language":"bash","snippet":"# Give the Keycloak service account only view-* roles (or an authentik token\n# without manage scope). A write then fails at the server, not on a flag a\n# model can argue around. Then:\nidentity-aiops doctor"},{"language":"bash","snippet":"export IDENTITY_AUDIT_APPROVED_BY=\"your.name@example.com\"\nexport IDENTITY_AUDIT_RATIONALE=\"access review 2026-07-20\""},{"language":"bash","snippet":"identity-aiops init                 # onboarding wizard (platform, base URL, realm, secret)\nidentity-aiops doctor               # config + secrets + token acquisition + user-count probe\nidentity-aiops doctor --skip-auth   # config/secrets checks only (no network)\nidentity-aiops overview             # one-shot estate summary\nidentity-aiops mcp                  # start the MCP server (stdio)"}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\nname: identity-aiops\nslug: identity-aiops\ndisplayName: \"Identity AIops\"\nsummary: \"Governed Keycloak + authentik identity ops: users, events, clients, MFA, RCA. 29 tools.\"\nlicense: MIT\nhomepage: https://github.com/AIops-tools/Identity-AIops\ntags: [aiops, mcp, governance, identity]\ndescription: >\n  Use this skill whenever the user needs to operate a Keycloak or authentik identity provider — a one-shot overview, realm settings, users with sessions/credentials/groups/lockout status, authentication and admin events, OAuth/OIDC clients, four flagship RCAs (login-failure/lockout-storm, stale access, client misconfiguration, MFA coverage), and governed writes (disable/enable a user, revoke sessions, require a password reset, replace redirect URIs, rotate a client secret).\n  Always use this skill for \"Keycloak\", \"authentik\", \"realm\", \"SSO users\", \"login failures\", \"brute force logins\", \"locked out users\", \"stale accounts\", \"service account misuse\", \"redirect URI\", \"PKCE\", \"implicit flow\", \"client secret rotation\", \"MFA coverage\", \"who has no 2FA\" when the context is a Keycloak/authentik IdP.\n  Do NOT use when the target is something other than a Keycloak/authentik identity provider (a hypervisor, storage appliance, backup product, container-orchestration cluster, firewall, database, or OT/industrial equipment) — route those to the appropriate other AIops-tools skill. Cloud IdPs (Okta, Entra ID, Auth0) are out of scope.\n  Governed identity operations with a built-in governance harness (audit, policy, token budget, undo, risk-tiers).\ninstaller:\n  kind: uv\n  package: identity-aiops\nargument-hint: \"[a user/client id, a realm, or describe your identity task]\"\nallowed-tools:\n  - Bash\nmetadata: {\"openclaw\":{\"requires\":{\"anyBins\":[\"identity-aiops\",\"uvx\"]},\"optional\":{\"env\":[\"IDENTITY_AIOPS_CONFIG\",\"IDENTITY_AIOPS_MASTER_PASSWORD\"]},\"homepage\":\"https://github.com/AIops-tools/Identity-AIops\",\"emoji\":\"🔐\",\"os\":[\"macos\",\"linux\"]}}\ncompatibility: >\n  Standalone, self-governed identity-provider operations across Keycloak (admin REST API /admin/realms/{realm}/..., OAuth2 client-credentials grant against the realm token endpoint with automatic refresh-on-401) and authentik (API v3 /api/v3/..., long-lived API token as a Bearer header). Each target in the config names its own platform, and a name-keyed platform registry selects the API shape, so the same tools work on both and one config can span a mixed estate. The governance harness (audit, policy, token/runaway budget, undo, risk-tiers) is bundled in the package — no external skill-family dependency.\n  All write operations are audited to a local SQLite DB under ~/.identity-aiops/ (relocatable via IDENTITY_AIOPS_HOME).\n  Credentials: the Keycloak confidential client's client secret or the authentik API token is stored ENCRYPTED in ~/.identity-aiops/secrets.enc (Fernet/AES-128 + scrypt-derived key) — never plaintext on disk. Run 'identity-aiops init' to onboard (it asks for the platform, base URL, and — Keycloak — rea"},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn7b067awq2s97bn3d7p5qfhw5827pxc\",\n  \"slug\": \"identity-aiops\",\n  \"version\": \"0.8.5\",\n  \"publishedAt\": 1789601143154\n}"},{"path":"references/agent-guardrails.md","content":"# Agent guardrails — running identity-aiops with a smaller / local model\n\nIf you drive these tools with a local model (Llama, Qwen, Mistral … via Goose,\nOllama, LM Studio, or any OpenAI-compatible runtime), you will get noticeably\nbetter results with a short system prompt. This page gives you one, and — more\nimportantly — tells you which guardrails you **no longer need to write**, because\nthe tool now enforces them itself.\n\nThe distinction matters. A guardrail in a prompt is a request. A guardrail in the\nharness is a guarantee. Anything below that we could move into the harness, we did.\n\n## Authorization is not this tool's job — decide it where it belongs\n\nWhether a write should happen is your decision, or the account's. The tool does\nnot gate it — there is no read-only switch and no approval prompt to configure.\nThe two right places to control read vs write:\n\n- **The account you connect with.** Give the Keycloak service account (or the\n  authentik token) only the roles you want the agent to have — `view-users` /\n  `view-events` / `view-clients` and no `manage-*`. A write then fails at the\n  server, which is the only place the permission actually lives — no skill-side\n  flag can be argued around by a model, but a revoked permission cannot be.\n- **Your agent's system prompt.** If you want an observe-only session, tell the\n  model not to call the write tools (they are clearly tagged `[WRITE]`).\n\nWhat the tool *does* guarantee is that you can always see what happened:\n\n## What the tool enforces — do not waste prompt budget on these\n\n| You might be tempted to prompt | Why you don't need to |\n|---|---|\n| \"Don't invent a value when a field is missing\" | A field the IdP did not return comes back as `null`, never as `\"\"`. Absent and empty are distinguishable in the payload — a `lastLogin` of `null` means \"no sign-in on record\", not \"signed in at an empty time\". |\n| \"Tell me if the output was cut off\" | Every listing returns `{\"users\": [...], \"returned\": N, \"limit\": L, \"truncated\": true/false}` (same shape for `events`, `groups`, `members`, `clients`, `sessions`, `identityProviders`). Truncation is measured — one extra row is fetched — not guessed from a length coincidence. |\n| \"Tell me if the analysis only saw part of the data\" | The four analyses echo `inputsTruncated` / `feedTruncated`, and `truncated` + `maxRows` when a finding list was capped. The `*Count` fields are always the full totals. |\n| \"Make it show the number it judged on\" | `client_misconfig_audit` ranks clients by `riskScore` — the summed severity weights, echoed as `severityWeights` so the score is recomputable — and every finding carries its own `severity`. `login_failure_rca` findings each carry the counts that tripped them (`failures`, `distinctUsers`, `distinctIps`); the thresholds they were compared against are reported separately under `thresholds`, not on the finding. |\n| \"Confirm before anything destructive\" | Write CLI commands have `--dry-run` plus double confirmation. |\n| \"Log"},{"path":"references/capabilities.md","content":"# identity-aiops capabilities\n\n> **29 MCP tools** (21 read, 6 write, 2 undo) across Keycloak (admin REST `/admin/realms/{realm}/...`,\n> client-credentials grant, refresh-on-401) and authentik (API v3 `/api/v3/...`,\n> Bearer token). The concrete REST paths below are modelled from each project's\n> public API and need live verification.\n\nA per-target `platform` field (`keycloak` / `authentik`) selects the API shape;\nthe same tool name resolves to the right path on each IdP via the platform\nregistry. Every substituted path segment (realm, user id, client id) is\npercent-encoded centrally.\n\n## Realm / system (read)\n\n| Tool | Keycloak path | authentik path | Returns |\n|------|---------------|----------------|---------|\n| `identity_overview` | (composite) | (composite) | platform/realm, user/client/IdP counts, failed-login feed size |\n| `realm_info` | `/admin/realms/{realm}` | `/api/v3/admin/system/` | brute-force protection, password/OTP policy (KC); version/environment (AK) |\n| `list_identity_providers` | `/admin/realms/{realm}/identity-provider/instances` | `/api/v3/sources/all/` | federated IdPs / sources with enabled state |\n\n## Users / groups (read)\n\n| Tool | Keycloak path | authentik path | Returns |\n|------|---------------|----------------|---------|\n| `list_users` | `/admin/realms/{realm}/users` | `/api/v3/core/users/` | normalized users (id, username, enabled, lastLogin, serviceAccount) |\n| `user_detail` | `/admin/realms/{realm}/users/{id}` | `/api/v3/core/users/{id}/` | one user incl. requiredActions/attributes |\n| `user_count` | `/admin/realms/{realm}/users/count` | `/api/v3/core/users/` (pagination.count) | total users — the doctor probe |\n| `user_sessions` | `/admin/realms/{realm}/users/{id}/sessions` | `/api/v3/core/authenticated_sessions/?user=` | active sessions (id, IP, start/last access) |\n| `user_credentials` | `/admin/realms/{realm}/users/{id}/credentials` | `/api/v3/authenticators/admin/all/?user=` | credentials/devices with second-factor flags |\n| `list_groups` | `/admin/realms/{realm}/groups` | `/api/v3/core/groups/` | groups |\n| `group_members` | `/admin/realms/{realm}/groups/{id}/members` | `/api/v3/core/groups/{id}/` (users_obj) | normalized member users |\n| `user_lockout_status` | `/admin/realms/{realm}/attack-detection/brute-force/users/{id}` | — (teaching error) | failure count, locked state, last failure IP |\n\n## Events (read)\n\n| Tool | Keycloak path | authentik path | Returns |\n|------|---------------|----------------|---------|\n| `login_events` | `/admin/realms/{realm}/events` | `/api/v3/events/events/` | normalized events {time, type, user, ip, client, error} |\n| `admin_events` | `/admin/realms/{realm}/admin-events` | `/api/v3/events/events/` (admin actions) | admin/config changes {operation, resource, actor, ip} |\n\n## Clients (read)\n\n| Tool | Keycloak path | authentik path | Returns |\n|------|---------------|----------------|---------|\n| `list_clients` | `/admin/realms/{realm}/clients` | `/api/v3/providers/oauth2/` | no"},{"path":"references/cli-reference.md","content":"# identity-aiops CLI reference\n\nAll read commands print normalized JSON. All write commands take `--dry-run`\n(preview, no call, no audit) and otherwise require **double confirmation**;\nconfirmed writes execute through the governed MCP twins, so they land in\n`~/.identity-aiops/audit.db` with undo where applicable. `--target/-t` selects\na target from config (default: the first one).\n\n## Setup / health\n\n```bash\nidentity-aiops init                 # onboarding wizard (platform, base URL, realm, secret)\nidentity-aiops doctor               # config + secrets + token acquisition + user-count probe\nidentity-aiops doctor --skip-auth   # config/secrets checks only (no network)\nidentity-aiops overview             # one-shot estate summary\nidentity-aiops mcp                  # start the MCP server (stdio)\n```\n\n## Secrets (encrypted store)\n\n```bash\nidentity-aiops secret set <target>    # store/replace a secret (hidden prompt)\nidentity-aiops secret list            # target names only — never values\nidentity-aiops secret remove <target>\nidentity-aiops secret migrate         # legacy .env / env vars → secrets.enc\n```\n\nMaster password: `IDENTITY_AIOPS_MASTER_PASSWORD` (non-interactive/MCP) or an\ninteractive prompt on a TTY.\n\n## Events\n\n```bash\nidentity-aiops events                          # recent auth events\nidentity-aiops events --type LOGIN_ERROR -n 50 # Keycloak failed logins\nidentity-aiops events --type login_failed      # authentik failed logins\nidentity-aiops events --user alice\n```\n\n## Users\n\n```bash\nidentity-aiops users list [--search alice] [--limit 200]\nidentity-aiops users show <user-id>\nidentity-aiops users sessions <user-id>\nidentity-aiops users credentials <user-id>          # MFA surface\n\n# governed writes\nidentity-aiops users disable <user-id> [--dry-run]          # med, undo: enable\nidentity-aiops users enable <user-id> [--dry-run]           # HIGH\nidentity-aiops users revoke-sessions <user-id> [--dry-run]  # med, irreversible\nidentity-aiops users require-reset <user-id> [--clear] [--dry-run]\n```\n\n## Clients\n\n```bash\nidentity-aiops clients list [--limit 200]\nidentity-aiops clients show <client-id>\n\n# governed writes\nidentity-aiops clients set-redirect-uris <client-id> -u https://a/cb -u https://b/cb [--dry-run]  # HIGH\nidentity-aiops clients rotate-secret <client-id> [--dry-run]                                       # HIGH, masked\n```\n\n## Environment variables\n\n| Variable | Purpose |\n|----------|---------|\n| `IDENTITY_AIOPS_HOME` | relocate all state (config, secrets, audit, undo) |\n| `IDENTITY_AIOPS_CONFIG` | alternate config.yaml path (MCP server) |\n| `IDENTITY_AIOPS_MASTER_PASSWORD` | unlock secrets.enc non-interactively |\n| `IDENTITY_AUDIT_APPROVED_BY` / `IDENTITY_AUDIT_RATIONALE` | optional audit annotations (who/why), recorded when set |\n| `IDENTITY_MAX_TOOL_CALLS` / `IDENTITY_MAX_TOOL_SECONDS` | session budget ceilings |\n| `IDENTITY_<TARGET>_SECRET` | legacy plaintext secret fallback (deprecated) |"}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":null,"editorialQuality":{"score":100,"threshold":65,"status":"thin","wordCount":2143,"uniquenessScore":41,"reasons":["uniqueness-below-45"]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-10T14:17:47.744Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-10-10T14:17:47.744Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-10T17:36:43.196Z","emptyReason":null},"items":[{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-10-09T19:11:12.944Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}