> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tracecat.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Custom registry

> Sync custom Python and YAML actions into Tracecat through your own registry: version, share, and reuse organization-specific automations across workspaces.

You can build your own actions and use them in agents and workflows through Tracecat's custom registry feature.

## Why use a custom registry

* Version control your code separate from Tracecat
* Reuse your custom actions in multiple agents and workflows
* Easily update your custom actions across all agents and workflows

## Permissions

Custom registry is an organization-level feature and syncs across all workspaces.
You must have the "Organization Admin" role to add and manage the custom registry.

## Installation

<Steps>
  <Step title="Clone the custom registry starter kit">
    Clone the [custom registry starter kit](https://github.com/TracecatHQ/custom-integrations-starter-kit) from GitHub.

    <Frame>
      <img src="https://mintcdn.com/tracecat/9IEnC4OWdnuB3EvN/img/custom-actions/clone-github-template.png?fit=max&auto=format&n=9IEnC4OWdnuB3EvN&q=85&s=eea42b8af83c33637d9afe4ee41aee91" alt="Clone GitHub template" width="1274" height="986" data-path="img/custom-actions/clone-github-template.png" />
    </Frame>
  </Step>

  <Step title="Add an SSH key">
    Tracecat clones the repository over SSH.
    Generate an SSH key pair and add the public key to the repository as a read-only deploy key (GitHub: repository Settings -> Deploy keys).

    Go to Organization settings -> Custom registry -> Repository, click "Add SSH key" in the SSH key section, and paste the private key.
    The name is fixed to `github-ssh-key` and the environment to `default`. Tracecat looks the registry key up by this exact name, whichever Git host you use.
    To rotate the key, click "Replace SSH key" in the same section.

    <Frame>
      <img src="https://mintcdn.com/tracecat/8rG7WkYQgVdaOGV-/img/custom-actions/github-ssh-key.png?fit=max&auto=format&n=8rG7WkYQgVdaOGV-&q=85&s=d2a7e42c0d3a497f0f70e903b7bc1491" alt="SSH key dialog" width="2880" height="1800" data-path="img/custom-actions/github-ssh-key.png" />
    </Frame>
  </Step>

  <Step title="Add registry to Tracecat">
    Go to Organization settings -> Custom registry -> Repository.

    Set the remote repository URL, repository package name, and allowed Git domains, then click "Save repository settings".
    The remote repository URL is a pip URL of the form `git+ssh://git@github.com/your-org/your-repo.git`.
    The package name is the name of the Python package (e.g. the parent folder named `custom_actions` in the starter kit) in the repo.

    <Frame>
      <img src="https://mintcdn.com/tracecat/8rG7WkYQgVdaOGV-/img/custom-actions/custom-registry-settings.png?fit=max&auto=format&n=8rG7WkYQgVdaOGV-&q=85&s=e3a6e809b742991ed3e9107ddcc4639e" alt="Custom registry settings" width="2880" height="1800" data-path="img/custom-actions/custom-registry-settings.png" />
    </Frame>
  </Step>

  <Step title="Sync the registry">
    Go to Organization settings -> Custom registry -> Versions.
    The table lists the commits on the branch named by the repository URL's `@ref` suffix (`main` when absent), newest first, with a `HEAD` badge on the latest.

    Click "Sync from remote" in the page header and confirm to sync `HEAD`.
    If the page shows an SSH error, check that the SSH key section on the Repository page lists `github-ssh-key` and that its public key is installed on the repository.

    <Frame>
      <img src="https://mintcdn.com/tracecat/8rG7WkYQgVdaOGV-/img/custom-actions/sync-from-remote.png?fit=max&auto=format&n=8rG7WkYQgVdaOGV-&q=85&s=6c65f610a355784485b9c7ca8d60511e" alt="Sync from remote" width="2880" height="1800" data-path="img/custom-actions/sync-from-remote.png" />
    </Frame>
  </Step>
</Steps>

## Manage versions

Each sync creates a version pinned to its source commit.
On the Versions page, every row shows the commit, its message and author, its status (`Current`, `Synced`, or `Not synced`), and when you last synced it.

Open the row menu to act on a version.

<Frame>
  <img src="https://mintcdn.com/tracecat/8rG7WkYQgVdaOGV-/img/custom-actions/change-commit.png?fit=max&auto=format&n=8rG7WkYQgVdaOGV-&q=85&s=4edd5db618ac3bb7de99c95bdf1a91aa" alt="Version actions" width="2880" height="1800" data-path="img/custom-actions/change-commit.png" />
</Frame>

* "Sync this commit" syncs a commit you have not synced yet.
* "Promote" makes an already-synced version the current one. Promote an earlier version to roll back.
* "Compare..." shows the actions added, removed, and modified between two versions.
* "Delete" removes a synced version. Tracecat blocks deletion of the current version and of any version that published workflows use.

Synced versions whose commit no longer appears in the commit list are grouped under "Other synced versions" below the table, with the same row menu.

## How custom registry works

When you sync a registry, Tracecat:

* Pulls the latest code from the remote repository
* Converts the package and its dependencies into a tarball using `uv`
* Uploads the tarball to S3-compatible object storage
* Tarballs are stored in the bucket specified in the `TRACECAT__BLOB_STORAGE_BUCKET_REGISTRY` environment variable

<Info>
  Published workflows run actions synced at the time of publication.
  When triggered, the Tracecat executor pulls the pinned version of the platform registry and custom registry tarballs from S3.

  You must republish a workflow to use the latest platform and custom actions.
  Even if there were no changes to the workflow itself.
</Info>

## FAQ

<AccordionGroup>
  <Accordion title="Does Tracecat support self-hosted Git repositories?">
    Yes. Tracecat works with Gitlab and GitHub Enterprise.
  </Accordion>

  <Accordion title="Can I rename my custom Python package name?">
    Yes. The package name from the starter kit is `custom_actions`.
    To rename it, you'll need to rename the:

    * `custom_actions` folder to `my_new_package_name`
    * Project name in `pyproject.toml` to `my_new_package_name`

    Note: Python package names must be snake\_case.
  </Accordion>

  <Accordion title="Can I rename the git repo?">
    Yes. You can rename the git repo. It does not need to have the same name as the Python package.
  </Accordion>

  <Accordion title="How can I add new Python dependencies?">
    You must specify new dependencies in the `dependencies` section of the `pyproject.toml` file.
  </Accordion>

  <Accordion title="Can I test actions without syncing on every change?">
    Yes. For local Docker deployments, you can hot reload custom actions into Tracecat with a local registry.
    See [local development](/custom-actions/local-development) for more details.
  </Accordion>
</AccordionGroup>
