Depotex raises an event for each important operation. Policies, automation and plugins react to these events: a policy can stop an operation before it happens, and automation or a plugin can act after it has happened.
1. Before and after
| Phase | When | What subscribers can do |
|---|---|---|
| Before | Before the operation runs | Stop it with a message (on events marked *blocking*), or adjust the few fields the event allows. They have a few seconds at most. |
| After | Once the operation has succeeded | React to it: send an alert, notify another system. They can't undo or slow down the operation. |
Passwords, keys and similar secrets are never included in an event.
2. Delivery
- After-events are saved in the database together with the change that caused them, so they are never lost when a server restarts, and each is delivered once across all servers of a cluster.
- They usually arrive within a few seconds.
- A subscriber that fails is retried with increasing delays (up to 8 times by default, over several hours); after that the delivery is marked as failed and kept for 30 days.
- The same event can occasionally be delivered twice (for example after a server restart mid-delivery). Plugins and integrations must handle repeats.
Events marked policies accept organization policies.
3. Available events
| Event | Phases | Blocking | When it happens |
|---|---|---|---|
| auth.login | before, after | yes · policies | A user signs in. Checked after the password is verified and before the session starts |
| auth.login.failed | after | no | A sign-in is refused (wrong credentials, inactive or locked account) |
| auth.logout | after | no | A user signs out |
| auth.session.revoke | after | no | Sessions are ended by a user, an admin or the system |
| user.create | before, after | yes · policies | An administrator creates a user |
| user.update | before, after | yes · policies | A user's email or name changes |
| user.disable | before, after | yes · policies | A user is disabled and signed out everywhere |
| user.enable | before, after | yes · policies | A disabled user is enabled again |
| user.role.change | before, after | yes · policies | A user's role changes |
| user.password.reset | before, after | yes · policies | An administrator sets a user's password |
| user.password.change | after | no | A user changes their own password |
| user.password.recover | after | no | A user sets a new password from a password reset email |
| user.invitation.accept | after | no | An invited user chooses a password and their account becomes active |
| mail.settings.update | before, after | yes | The email settings change (SMTP server or Amazon SES API, sender, Depotex address) |
| storage.settings.update | before, after | yes | The storage settings change (location, credentials or upload limits) |
| backup.create | before, after | yes | A backup starts (manual or scheduled); after carries its SHA-256, path and size. See Backups |
| backup.verify | after | no | A backup's integrity check finished: ok, the level reached and the signature result |
| backup.fail | after | no | A backup couldn't be written (stage: write) or failed its check (stage: verify), with the reason |
| backup.update | before, after | yes | A backup's Keep permanently or note changes |
| backup.delete | before, after | yes | A backup is deleted by a person or by the cleanup job (by); a refused cleanup deletion is skipped |
| backup.download | before, after | yes | A backup is downloaded (it holds the whole database) |
| backup.restore | before, after | yes | A backup is restored over the installation; after (raised in the database that is live afterwards) carries state (done, failed), step, reason, rolled_back and the safety backup |
| backup.upload | before, after | yes | A backup is brought in: source (upload, import, cli), file name and size; after carries the backup it became |
| backup.settings.update | before, after | yes | Backup encryption or row counting changes: encrypt, mode, recipients (public keys), passphrase_changed, row_counts; never the passphrase |
| backup.target.update | before, after | yes | The backup target changes: separate, backend, location, whether it was adopted; never credentials |
| backup.test_restore | before, after | yes | A test restore starts (trigger: person or schedule) and finishes: status, reason, tables, rows and mismatches |
| repository_settings.update | before, after | yes | The repository settings change (largest artifact, timeouts, retries, outbound proxy) |
| repository_settings.proxy_checksums.update | before, after | yes | Settings → Security → Proxy checksums is turned on or off (previous_strict shows the old value, formats the formats whose new proxies start at it) |
| trusted_certificate.create | before, after | yes | A CA certificate is added to the trust store for remote registries |
| trusted_certificate.delete | before, after | yes | A CA certificate is removed from the trust store |
| vibe.settings.update | before, after | yes | A vibe artifacts setting changes (Enterprise): turned on or off (turning off keeps what was published), whether secrets and hidden characters refuse a push, or the package list address |
| user.anonymize | before, after | yes · policies | A disabled user is anonymized (GDPR erasure); subscribers should erase what they hold about the user ID |
| user.unlock | after | no | An administrator unlocks an account locked after failed sign-ins |
| group.create | before, after | yes · policies | An administrator creates a group |
| group.update | before, after | yes · policies | A group is renamed or its description changes |
| group.delete | before, after | yes · policies | An administrator deletes a group (sync never deletes groups) |
| group.member.add | before, after | yes · policies | An administrator adds users to a group |
| group.member.remove | before, after | yes · policies | An administrator removes a member added by hand |
| space.create | before, after | yes · policies | A super admin creates a space (policies can, for example, forbid internal spaces or limit formats); the payload carries the storage quota asked for, absent when the installation default applies |
| space.update | before, after | yes · policies | A space's name, description, visibility or formats change (previous_visibility shows the old visibility) |
| space.delete | before, after | yes · policies | A space is deleted, with everyone's roles in it |
| upstream.create, upstream.update, upstream.delete | before, after | yes | A super admin adds, changes or removes an upstream registry (never with its credentials) |
| space.upstreams.update | before, after | yes | The upstreams a space may proxy change (new and previous lists) |
| artifact.upload | before, after | yes · policies | A file is about to be stored in a repository (space, repository, format, path, size, version, overwrite, and the group it came through); space upload rules and policies can refuse it |
| vibe.checkin.push | before, after | yes · policies | A check-in is pushed to a vibe artifacts project (Enterprise): before, with the project, milestone, file count, size, screenshots and what the push check found (a policy can refuse it, for example on high findings); after, with the check-in's number, what it builds on, how many files changed and its link in the Vibe browser |
| vibe.milestone.update | before, after | yes · policies | A vibe artifacts check-in's milestone is named, renamed or cleared after its push, from the Vibe browser (Enterprise): space, repository, project, check-in, the new name and the previous one |
| vibe.project.delete | before, after | yes · policies | A vibe artifacts project is deleted with all its check-ins (space, repository, project, number of check-ins) |
| depot.repository.update | before, after | yes · policies | A repository's settings change (online, write, version and layout policies, size limit, upstream, proxy settings), or a group's members and policies |
| depot.space.default_group | before, after | yes · policies | A group becomes a space's default for its format (its universal URL), or the default is removed (space, format, group, previous group) |
| repository.repair | before, after | yes · policies | A repository's metadata is rebuilt from its stored files: asked for (before: space, repository, format, mode check or repair) and run (after: state and report of files checked, problems found and fixed) |
| tag.create, tag.update, tag.delete | before, after | yes · policies | A space's tag is added, changed (description, attributes) or removed (space, name, description, attributes) |
| artifact.promote | before, after | yes · policies | Versions are promoted (copied or moved) to another repository: source and target, move or copy, the tag used, each version with its tags (before), and how many were promoted or refused (after) |
| artifact.tag | before, after | yes · policies | A tag is put on versions or taken off them (space, tag, add or remove, the versions; upload when it came with X-Depotex-Tag). Refusing it on upload refuses the upload |
| content_selector.create, .update, .delete | before, after | yes · policies | A space's content selector (named path patterns) is created, changed or deleted |
| content_selector.grant, .revoke | before, after | yes · policies | A user or group gets, or loses, a repository role on the paths a content selector matches |
| artifact.integrity.broken | after | no | The integrity check found stored content missing or changed (counts); the files using it are hidden |
| artifact.integrity.repair | before, after | yes | The integrity repair deletes broken files and orphaned content (counts, bytes freed) |
| upstream.blocked | after | no | A host of an upstream (its own, or one its files come from) failed repeatedly and is paused (key, host, failures, until); proxy repositories serve their cache from it meanwhile, and the upstream's other hosts keep working |
| proxy.cache.invalidate | before, after | yes · policies | A repository admin makes a proxy repository ask its upstream again: forgets remembered “not found” answers (scope not_found) or also re-checks cached files (scope all), for one path, a folder or all (space, repository, path, how many answers were forgotten and files will be re-checked); policies can refuse it |
| proxy.artifact_withdrawn | after | no | A file cached from a linked Depotex is removed because that Depotex quarantined or blocked it (space, repository, upstream, path, status); alert or notify on it |
| artifact.quarantine | before, after | yes · policies | A version is quarantined (space, repository, format, name, version, reason, rule, until): by hand (before and after), by a quarantine rule on upload or proxy fetch (after), or automatically when Depotex refuses unsafe content the version carries (after, source guard; see Browse); a vulnerable-version rule adds advisories, fixed_version and pending_check; notify on it with automation |
| artifact.release | before, after | yes · policies | A quarantined version is released (note, who): by hand (before, refused if a subscriber fails, and after) or when an age rule ends (after, release_source expired) or a version held until it was checked for vulnerabilities turns out clean (after, release_source checked) |
| quarantine.vulnerability.found | after | no | New advisories name a stored version a vulnerable-version rule would hold (space, repository, name, version, rule, advisories, fixed_version) and say what happened: action alert, quarantined, or pending with due_at; notify or open a ticket with automation |
| quarantine.rule.create, .update, .delete | before, after | yes · policies | A quarantine rule of the installation or a space is added, changed or removed |
| blocklist.rule.create, .update, .delete | before, after | yes · policies | A block-list rule of the installation or a space is added, changed or removed; a failing subscriber refuses the change |
| sbom.application.create, .delete | before, after | yes · policies | An application (software whose SBOMs are uploaded) is registered in a space or deleted with its versions (space, key, name, description) |
| sbom.document.upload, .delete | before, after | yes · policies | An SBOM is uploaded for an application version, after it was read (space, application, version, file name, size, format, spec version, tool, component count, truncated), or deleted; policies can refuse a format or a document with too few components |
| sbom.vulnerability_data.update | before, after | yes | The vulnerability data settings change (enabled, source, endpoint or data files address, recheck hours) |
| sbom.rescan.request | before, after | yes | Someone asks for components to be checked again now (re-check) or for versions to be read again (re-inspect: SBOMs rebuilt, images optionally scanned again), for one version, a repository or the installation (scope, mode, images, space, repository, version). Policies can refuse it |
| sbom.vulnerability_data.import | after | no | Vulnerability data is imported: downloaded from the data files address (one ecosystem, whole or only the changes), from an uploaded file, or a distribution's advisories read from its repositories (source feed); how many advisories were stored and skipped. Automation can report when the data was last refreshed |
| sbom.vex.update, .delete | before, after | yes · policies | A VEX statement about a vulnerability in one SBOM is made, changed or removed (space, document, owner, advisory, state, justification, response, detail); policies can require a justification for not_affected |
| sbom.document.evaluate | before, after | yes · policies | An SBOM is evaluated after an artifact version's SBOM was read, when an application SBOM is uploaded, and when new advisories match it (space, owner, repository, name, version, licenses, component counts, known vulnerabilities with VEX applied, max_severity, trigger, origin, coverage, coverage_score, version_coverage, documents, findings, not_covered: how many components no vulnerability data covers); also raised for a version without any SBOM (documents 0); a denial quarantines the version (source policy) or refuses the upload |
| sbom.share.create | before, after | yes · policies | A link to an SBOM export that anyone can open is made (space, owner, name, version, format, with VEX, days); policies can forbid sharing or cap the days |
| sbom.vulnerability.found | after | no | New advisories match the components of one SBOM (space, owner, name, version, advisories worst first, max_severity, summary, open critical and high counts); space owners and maintainers get one alert per space and round of checks; forward it with automation |
| sbom.vulnerability.resolved | after | no | Advisories no longer affect one SBOM (space, owner, name, version, advisories, reason: no_longer_matches after a re-check, or vex); close what automation opened |
| sbom.scan.complete | after | no | Every component of a newly stored version's SBOMs has been checked (space, repository, name, version, documents, coverage, counts by severity, checked, and not_covered: components no vulnerability data covers, so all counts 0 with not_covered above 0 means nothing could be checked, not a clean scan); raised once per version and inspection, not by daily re-checks |
| artifact.block | before, after | yes · policies | A quarantined version is blocked from quarantine (space, repository, format, name, version, note, scope, all_versions, rule_id, checksums, files): it stays stored and a block-list rule refuses it; policies can refuse it, for example to keep installation-wide blocks to a team |
| artifact.reject | before, after | yes · policies | A quarantined version is deleted and blocked (same fields as artifact.block); artifact.delete follows for each file; policies can refuse it |
| artifact.blocked | after | no | A request for a blocked version was refused (space, repository, path, name, version, rule, user); at most once per version and server every 10 minutes |
| pypi.release.yank | before, after | yes · policies | A PyPI release is yanked or un-yanked (space, repository, project, version, yanked, reason); installers skip a yanked release unless it's pinned; policies can refuse it |
| nuget.package.list | before, after | yes · policies | A NuGet package version is unlisted or relisted (space, repository, id, version, listed); unlisted versions leave search but still restore when referenced exactly; policies can refuse it |
| nuget.settings.update | before, after | yes · policies | A hosted NuGet repository's delete mode changes (space, repository, delete_mode: unlist or delete) |
| cargo.crate.update | before, after | yes · policies | A crate of a hosted Cargo repository changes (space, repository, crate, version, action, owners): a version yanked or unyanked (yank, unyank), owners added or removed (add_owners, remove_owners), its name reserved or released (reserve, unreserve), or a version's docs uploaded, built, removed or queued to build (docs, delete_docs, build_docs); policies can refuse it |
| huggingface.repo.update | before, after | yes · policies | A Hugging Face repository is created or deleted, its private flag changes, or a branch or tag is created or deleted |
| gitlfs.lock.create | before, after | yes · policies | A file is locked in a Git LFS repository (git lfs lock) |
| gitlfs.lock.delete | before, after | yes · policies | A Git LFS lock is released (git lfs unlock), with force when it was someone else's |
| composer.package.abandon | before, after | yes · policies | A Composer package is marked abandoned (with an optional replacement) or no longer |
| composer.settings.update | before, after | yes · policies | A Composer repository's settings change (hosted packages hide upstream ones, keep git sources, whether a GitHub token is stored; never the token) |
| rubygems.gem.update | before, after | yes · policies | One platform's file of a gem version in a hosted RubyGems repository is yanked or restored (space, repository, gem, version, platform, action: yank, unyank); policies can refuse it |
| rubygems.gem.ownership | before, after | yes · policies | A gem's owners change in a hosted RubyGems repository, or a gem name is reserved for its owners or released (space, repository, gem, action: add_owner, remove_owner, reserve, unreserve, owner id and user name, never an email); refused when policies can't be read |
| rubygems.settings.update | before, after | yes · policies | A RubyGems repository's settings change (space, repository, owners only, new names admin only, hosted gems hide upstream ones); refused when policies can't be read |
| conda.version.update | before, after | yes · policies | Builds of a version in a hosted conda repository are yanked or restored (space, repository, package, version, files, action yank or unyank, reason); yanked builds leave the channel's index but stay downloadable; policies can refuse it |
| conda.settings.update | before, after | yes · policies | A conda repository's settings change (space, repository, whether it serves sharded repodata and, for a group, whether hosted packages hide upstream packages of the same name); refused when a subscriber can't be reached |
| conan.revision.publish | before, after | yes · policies | A recipe revision or a binary's package revision is complete in a hosted Conan repository and about to become installable (space, repository, reference, recipe revision, and for a binary its package ID, package revision and settings; files, size, integrity); not raised again when a client uploads it again; policies can refuse it |
| conan.revision.delete | before, after | yes · policies | A Conan recipe revision with its binaries, or one package revision, is deleted by a client or from the browser, also one a proxy has kept (same fields as conan.revision.publish, and cached: true for a proxy's; the upstream keeps it); artifact.delete follows for each file; policies can refuse it. Not raised when revisions go with their whole version (cleanup, the trash, a quarantined version deleted, the repository deleted), which raise their own events |
| conan.settings.update | before, after | yes · policies | A Conan group's settings change (space, repository, whether hosted recipes hide upstream recipes of the same name); refused when a subscriber can't be reached |
| cargo.settings.update | before, after | yes · policies | A Cargo repository's settings change (space, repository, owners only, new names admin only, hosted crates hide upstream ones, build docs, docs size limit) |
| apt.settings.update | before, after | yes · policies | An APT repository's settings change: Release validity, a group's architectures, a proxy's upstream keys (space, repository, architectures, valid_days, upstream_keys) |
| yum.settings.update | before, after | yes · policies | A hosted YUM repository's or proxy's settings change (space, repository, repodata depth, trusted package keys, require signatures, require signed repodata); a new depth moves every package's address |
| repository.signing_key.update | before, after | yes · policies | An APT, YUM or Terraform repository's signing key is rotated or replaced by an imported one, at once or after an overlap; a pending switch is brought forward, cancelled, or takes effect (activate, after only) (space, repository, format, action, fingerprint, previous fingerprint, activates_at); clients must trust the new key before it signs |
| npm.package.update | before, after | yes · policies | A published npm package changes: versions unpublished (or the whole package), deprecated, dist-tags moved, owners or stars changed (space, repository, package, action, versions, tag); policies can refuse it, for example to forbid unpublishing |
| artifact.delete | before, after | yes · policies | A file is deleted from a repository (space, repository, path, size, SHA-256, version); policies can refuse it, for example to protect releases |
| space.upload_rules.update | before, after | yes · policies | A space's upload rules change (limits, default and number of rules) |
| space.cleanup_policy.create, .update, .delete | before, after | yes · policies | A space's cleanup policy is added, changed or removed |
| cleanup.run | after | no | A cleanup policy ran: versions moved to the trash, bytes, the run's trash reason (to undo it), or the error |
| artifact.restore | before, after | yes · policies | Trashed versions are restored (space, versions, bytes they add back); the space's quota and policies can refuse it |
| artifact.purge | before, after | yes · policies | Trashed versions are deleted for good on request, before the trash is emptied (space, versions, bytes freed); policies can refuse it |
| space.quota.update | before, after | yes | A super admin sets, changes or removes a space's storage quota |
| space.quota.warning | after | no | A space's storage passed its warning threshold or reached its quota (checked hourly; level warning or full) |
| access.grant | before, after | yes · policies | A user or group is given a role on a space, or their role there changes (previous_role shows the old one). Policies can, for example, refuse the Owner role to groups |
| access.revoke | before, after | yes · policies | A user's or group's role on a space is removed |
| directory.create | before, after | yes | A directory is added (last in the order) |
| directory.update | before, after | yes | A directory is renamed, enabled or disabled |
| directory.delete | before, after | yes | An empty directory is deleted |
| directory.sync | after | no | A directory sync finished, failed or was blocked by a safety check |
| directory.reorder | after | no | Directories are put in a new order |
| sso.provider.create | before, after | yes | An identity provider for single sign-on is added |
| sso.provider.update | before, after | yes | An identity provider is changed, turned on or turned off |
| sso.provider.delete | before, after | yes | An identity provider is removed |
| security.captcha.update | before, after | yes | The CAPTCHA settings change (provider, keys, which events ask) |
| system.check.completed | after | no | A system check run finished |
| system.check.changed | after | no | A system check found something worse than the previous run, or everything recovered |
| cluster.health.changed | after | no | The cluster health status (ok, warning, problems) changed and held for two minutes |
| system_check.settings.update | before, after | yes | Who is notified about system check changes, and how, changes |
| alert.silence.create | before, after | yes | A mute is added on Alert tuning |
| alert.silence.update | before, after | yes | A mute's end or reason changes |
| alert.silence.ended | after | no | A mute ended: removed, expired, or its problem cleared |
| alert.tuning.update | before, after | yes | A check's notification rule or thresholds change, or are reset |
| alert.incident.resolved | after | no | A System health alert is OK again |
| log_alert_rule.create, log_alert_rule.update, log_alert_rule.delete | before, after | yes | A log alert rule is added, changed (including turned on or off) or removed |
| log.alert.fired | after | no | A log alert rule matched enough log lines and fired |
| logging.settings.update | before, after | yes | The logging settings change (levels, temporary levels, log file) |
| auth.session_policy.update | before, after | yes | The session settings change (inactivity limit, maximum length, Remember me, sessions per person) |
| sso.enforcement.update | before, after | yes | Requiring single sign-on is turned on or off, or the super-admin password exception changes |
| security.anonymous_access.update | before, after | yes | Anonymous access to public spaces is turned on or off (previous_enabled shows the old value) |
| security.rate_limits.update | before, after | yes | The installation's rate limits or download quotas change in Settings → Security → Rate limits |
| security.rate_limit_override.create, .update, .delete | before, after | yes | A rate limit override or download quota for a role, organization, user, API token, AI app or repository is added, changed or removed |
| security.download_quota.reached | after | no | A person, token, AI app, organization or repository reached the warning level or the limit of a download quota (once per period and level) |
| site.settings.update | before, after | yes | The Depotex address (used in email links and single sign-on), the other addresses clients use, or whether package links use only these addresses changes |
| site.help.update | before, after | yes | The Help menu links change or are reset to the defaults |
| branding.update | before, after | yes | The app name, brand colors, logos or browser icons change |
| banner.create | before, after | yes | An announcement banner is created |
| banner.update | before, after | yes | A banner's title, text, kind, audience, schedule or switch changes |
| banner.delete | before, after | yes | A banner is deleted |
| oauth.client.create | before, after | yes | An OAuth application is registered |
| oauth.client.update | before, after | yes | An OAuth application is changed, enabled, disabled or gets a new secret |
| oauth.client.delete | before, after | yes | An OAuth application is removed |
| oauth.consent.grant | before, after | yes | A person allows an OAuth application (org policies can refuse it) |
| oauth.consent.revoke | after | no | A connection to an OAuth application ends |
| oauth.federation.create | before, after | yes | An OAuth application starts trusting a CI system's identity tokens |
| oauth.federation.update | before, after | yes | A workload identity trust rule changes or is turned off or on |
| oauth.federation.delete | before, after | yes | A workload identity trust rule is removed |
| applink.create | before, after | yes | A link with another Depotex installation is started here or accepted from the other side |
| applink.update | before, after | yes | A link becomes active or gets new credentials |
| applink.delete | before, after | yes | A link with another installation is removed |
| applink.connect | before, after | yes | A person connects their own account on a linked installation |
| service_account.create | before, after | yes | A service account is created |
| service_account.update | before, after | yes | A service account is renamed, gets another role, or is turned off or on |
| service_account.delete | before, after | yes | A service account is deleted |
| mcp.key.create | before, after | yes | A person makes an MCP key for an AI agent |
| mcp.key.revoke | before, after | yes | An MCP key is revoked by its owner or an administrator |
| ai_agents.mcp_keys.update | before, after | yes | MCP keys are allowed or stopped for the installation (off stops every key) |
| ai_agents.settings.update | before, after | yes | Write tools for AI agents are allowed or stopped for the installation |
| plugin.settings.update | before, after | yes | A plugin's settings, MCP mode (read-only or read-write) or switched-off tools change |
| plugin.data.delete | before, after | yes | A plugin's data is deleted: uninstalled with its data, restarted with its data reset, or its leftover data deleted |
| apitoken.create | before, after | yes · policies | A user creates an API token |
| apitoken.update | before, after | yes · policies | A token is renamed or its IP allowlist changes |
| apitoken.rotate | before, after | yes · policies | A token's secret is replaced |
| apitoken.revoke | after | no | Tokens are revoked by their owner or an admin |
| apitoken.org_policy.update | before, after | yes · policies | The organization's token rules change |
| avatar.update | before, after | yes · policies | A user sets a preset or uploads an avatar |
| avatar.delete | after | no | A user removes their avatar |
| alert.create | before, after | yes · policies | An alert is sent to users |
| license.apply | after | no | An admin applies a new license |
| cluster.node.rename | before, after | yes | An admin renames a cluster node |
| scheduler.job.update | before, after | yes | A job is enabled, disabled or rescheduled |
| scheduler.job.trigger | before, after | yes | A job is run by hand |
| scheduler.job.run | before, after | yes | A scheduled job runs; stopping it records the run as skipped |
| scheduler.job.unhealthy | after | no | A job failed several times in a row (SCHEDULER_UNHEALTHY_THRESHOLD) |
| scheduler.job.recovered | after | no | A job that was failing ran successfully again |
| depot.repository.create | before, after | yes · policies | A repository is created in a space |
| depot.repository.delete | before, after | yes · policies | A repository is deleted: it disappears at once and can be restored until it is removed for good |
| depot.repository.restore | before, after | yes · policies | A super admin restores a deleted repository, with its files, roles and settings |
| depot.repository.purge | before, after | yes · policies | Before: a super admin deletes a deleted repository permanently (a policy can refuse it). After: a deleted repository was removed for good, on request or after being kept long enough |
Signing out, revoking sessions or tokens, and failed sign-ins can't be blocked: ending access always works.
4. What each event carries
| Event | Fields |
|---|---|
| auth.login | Before: user id, email, role, IP address, browser, remember me (policies may turn remember me off). After: also the session |
| auth.login.failed | Email, IP address, reason |
| user.create | Before: email, name, role, directory, whether a new password is required (policies may require one). After: user id, email, name, role, status, directory. Never the password |
| user.update, user.disable, user.enable, user.unlock, user.password.* | User id, email, role (and the new email or name for updates) |
| user.role.change | User id, email, old role, new role |
| user.anonymize | User id and directory id only |
| user.password.recover, user.invitation.accept | User id and kind |
| mail.settings.update | Enabled, provider, transport (smtp or ses_api), SES region and role ARN, host, port, security, from address, Depotex address (never the password) |
| storage.settings.update | Backend, location, endpoint, region, upload limit, part size, whether the location or credentials changed (never credentials) |
| repository_settings.update | Largest artifact, timeouts, retries, proxy on/off, proxy URL and username, no-proxy list (never the password) |
| repository_settings.proxy_checksums.update | strict (the new value), previous_strict, formats |
| trusted_certificate.* | Id, name, subject, issuer, SHA-256 fingerprint, expiry |
| vibe.settings.update | Enabled, refuse secrets, refuse hidden characters, package list address, each with its previous value |
| vibe.checkin.push | Space, repository, project, whether it's new, milestone, what changed, file count, size, screenshots, test_passed, findings (counts per severity), max_finding_severity, finding_rules; after also the check-in number, parent, changed files and link |
| vibe.milestone.update | Space, repository, project, check-in number, milestone (empty when cleared), previous_milestone |
| vibe.project.delete | Space, repository, project, number of check-ins |
| group.create, group.update, group.delete | Group id, name, description |
| group.member.* | Group id and name, user ids |
| directory.create | Before: type, name. After: also id, enabled, position |
| directory.update, directory.delete | Directory id, type, name, enabled, position |
| directory.sync | Directory id, run id, status (success, partial, failed, blocked), dry run, error, counts of users and groups created, updated, disabled, merged and removed |
| directory.reorder | Directory ids, highest first |
| sso.provider.create, sso.provider.update, sso.provider.delete | Provider id, type (oidc or saml), name, on or off, directory id, whether accounts are created on first sign-in. Never secrets |
| site.settings.update | The Depotex address, the other addresses clients use (other_hosts), and whether package links use only these addresses (strict_links) |
| site.help.update | The six links, your own links, and whether they were reset |
| branding.update | App name, per-theme color, logo and icon, high-contrast switch |
| banner.* | Banner, title, message, kind, audience, closable, start, end, on |
| oauth.client.* | Application ID, client ID, name, kind (app or mcp), type, redirect addresses, scopes, approval, groups, enabled, token lifetimes, the plugins an AI agent may use, whether an AI agent's tools may change Depotex (mcp_access) (never the secret) |
| oauth.consent.grant | Application, user, scopes, whether pre-approved |
| oauth.consent.revoke | Connection, application, user, and who revoked it (user, admin, app_deleted) |
| service_account.* | ID, name, role, enabled |
| oauth.federation.* | Rule, application, name, issuer, audience, conditions, enabled |
| applink.* | Link, the other installation's name and address, directions, what it acts as, status (never credentials); applink.connect adds the person |
| mcp.key.* | Key id, owner, plugin, name, permissions, read or read-and-change, IP allowlist, expiry, who acted (never the key) |
| ai_agents.mcp_keys.update | Allowed, and the previous value |
| ai_agents.settings.update | Whether write tools are allowed, and the previous value |
| plugin.settings.update | Plugin, setting values, read-write mode, tools switched off, each with its previous value |
| plugin.data.delete | Plugin id and name, its data key, why (uninstall, reset or leftover), whether its database and key-value data are deleted, how many secrets |
| security.captcha.update | Provider, site key, puzzle size, the three switches and the failure count. Never the secret key |
| security.rate_limits.update | The saved settings and the previous ones |
| security.rate_limit_override.* | The override (scope, class, counts, budget or quotas, exempt, dry run, note); on update also the previous one |
| security.download_quota.reached | Level (warning or exceeded), scope and its id, period (day or month) and which one, quota and bytes used, whether it is enforced, the person (when it's theirs) |
| system.check.completed | Run id, scheduled or on demand, status (ok, warn, fail), counts |
| system.check.changed | Run id, status, previous status, the changed checks with their old and new status |
| cluster.health.changed | New status, previous status, what needs attention (server, check, status, code) |
| system_check.settings.update | In-app alert and email on or off, roles notified |
| alert.silence.* | The mute (id, source, check, item, server, end, until the problem clears, reason, who made it); alert.silence.ended adds why it ended |
| alert.tuning.update | Check, notify on, wait, reminders, thresholds, who changed it |
| alert.incident.resolved | Alert group, the severity it had before, the problems it last told |
| log_alert_rule.* | Rule id, name, on or off, lowest level, pattern, severity, roles notified |
| log.alert.fired | Rule id and name, severity, number of matching lines, window in minutes, an example line |
| logging.settings.update | Global level, per-part levels (with end time for temporary ones), log file on or off, name pattern, format, size, rotation and retention |
| auth.session_policy.update | Inactivity limit in minutes (0 = off), maximum length in hours, whether Remember me is offered, remembered length in days, sessions per person |
| sso.enforcement.update | Whether single sign-on is required, and whether super admins may still use a password |
| apitoken.* | Token id, owner, name, permissions, expiry, IP allowlist — never the token itself |
| apitoken.org_policy.update | Maximum lifetime, maximum tokens per user, request limit, blocked permissions |
| avatar.update | User, preset or upload, file type and size |
| alert.create | category, severity, target, title, message, message keys and values, image, actions, expiry, creator |
| license.apply | License id, licensee, tier, expiry, user and node limits |
| scheduler.job.* | Job name; for updates the new settings; for runs the status, duration and any error |
| depot.repository.create | Before: name, format, description, space_id, space_key, type, upstream, checksum_policy (a proxy's starting Checksums: strict, warn, off or default for Use the Security setting; empty for other types), and for a group its members and policies (subscribers may adjust the description). After: id, name, format, space_id, space_key, type |
| depot.repository.delete | Before and after: id, name, format, space_id, space_key |
| depot.repository.restore, depot.repository.purge | Before and after: id, name, format, space_id, space_key, type, upstream |
5. Failed deliveries
Settings → Advanced → Event deliveries (super admins) lists events that couldn't be delivered to a subscriber after every retry, with the last error. Retry once the problem is fixed, or Discard it. Failed deliveries are kept for 30 days (EVENT_DEAD_RETENTION_DAYS).
6. Performance
- An event nobody listens to costs nothing measurable.
- Before-subscribers (policies, plugins) run while the user waits: each adds to the time the action takes, up to the time limit below. Keep them simple.
- Once something listens to an after-event, every occurrence writes to the database and is delivered in the background. On frequent events such as auth.login or busy scheduled jobs, many subscribers or slow ones add database load and delivery backlog. Subscribe only to the events you need.
- Using an API token is deliberately not an event: a check on every request would slow down all API traffic. Use token settings and the organization's token rules instead.
On a busy installation, a slow or failing after-subscriber on a frequent event (for example every sign-in) builds up retries in the database. Watch the delivery settings below and keep such subscribers fast.
7. Time limits
| Variable | Default | Description |
|---|---|---|
| PLUGIN_PREHOOK_TIMEOUT | 5s | How long a before-subscriber may take before the operation is stopped (or the subscriber skipped, if it chose that) |
| PLUGIN_POSTHOOK_TIMEOUT | 30s | How long a plugin's after-hook may take before it is cancelled |
| EVENT_SUBSCRIBER_TIMEOUT | 30s | How long an after-subscriber may take per attempt |
8. Delivery settings
| Variable | Default | Description |
|---|---|---|
| EVENT_DISPATCH_INTERVAL | 5s | How often pending events are delivered |
| EVENT_MAX_ATTEMPTS | 8 | Attempts before a delivery is marked as failed |
| EVENT_RETRY_BASE_DELAY / EVENT_RETRY_MAX_DELAY | 5s / 1h | Wait between attempts: doubles each time, up to the maximum |
| EVENT_DISPATCH_BATCH / EVENT_DISPATCH_CONCURRENCY | 100 / 4 | Events claimed per round, and processed in parallel per server |
| EVENT_DELIVERY_LEASE | 2m | How long a server reserves an event it is delivering; after that another server takes over |
| EVENT_OUTBOX_RETENTION_DAYS / EVENT_DEAD_RETENTION_DAYS | 7 / 30 | How long delivered and failed events are kept |