Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/conda/conda/llms.txt

Use this file to discover all available pages before exploring further.

Overview

The CondaSpecs class defines all available plugin hook specifications. Each hook allows you to extend conda’s functionality in a specific way.
All hook implementations must be decorated with @plugins.hookimpl and follow the naming convention conda_<hook_name>.

Available Hooks

conda_solvers

Register custom solver implementations in conda. Returns: Iterable[CondaSolver] Example:
import logging
from conda import plugins
from conda.core import solve

log = logging.getLogger(__name__)


class VerboseSolver(solve.Solver):
    def solve_final_state(self, *args, **kwargs):
        log.info("My verbose solver!")
        return super().solve_final_state(*args, **kwargs)


@plugins.hookimpl
def conda_solvers():
    yield plugins.types.CondaSolver(
        name="verbose-classic",
        backend=VerboseSolver,
    )
  • The backend parameter must be a subclass of conda.core.solve.Solver
  • Users can select your solver with conda install --solver=verbose-classic
  • Only one solver with a given name can be registered

conda_subcommands

Register external subcommands in conda. Returns: Iterable[CondaSubcommand] Example:
from conda import plugins


def example_command(args):
    print("This is an example command!")


@plugins.hookimpl
def conda_subcommands():
    yield plugins.types.CondaSubcommand(
        name="example",
        summary="example command",
        action=example_command,
    )
  • The action callable receives parsed arguments from argparse
  • Should return an integer exit code (0 for success)
  • Use configure_parser to add custom CLI arguments

conda_virtual_packages

Register virtual packages in conda. Returns: Iterable[CondaVirtualPackage] Example:
from conda import plugins


@plugins.hookimpl
def conda_virtual_packages():
    yield plugins.types.CondaVirtualPackage(
        name="my_custom_os",
        version="1.2.3",
        build="x86_64",
    )
  • Virtual packages represent system capabilities (OS, CPU, GPU, etc.)
  • They can be used as dependencies in package recipes
  • The version and build can be static values or callables

conda_pre_commands

Register pre-command functions that run before specified conda commands. Returns: Iterable[CondaPreCommand] Example:
from conda import plugins


def example_pre_command(command):
    print("pre-command action")


@plugins.hookimpl
def conda_pre_commands():
    yield plugins.types.CondaPreCommand(
        name="example-pre-command",
        action=example_pre_command,
        run_for={"install", "create"},
    )
  • run_for specifies which commands trigger this hook
  • The action receives the command name as a string parameter
  • Useful for validation, logging, or preparation tasks

conda_post_commands

Register post-command functions that run after specified conda commands. Returns: Iterable[CondaPostCommand] Example:
from conda import plugins


def example_post_command(command):
    print("post-command action")


@plugins.hookimpl
def conda_post_commands():
    yield plugins.types.CondaPostCommand(
        name="example-post-command",
        action=example_post_command,
        run_for={"install", "create"},
    )
  • Executes after the main command completes successfully
  • Useful for cleanup, reporting, or triggering follow-up actions
  • Multiple post-command hooks can be registered

conda_auth_handlers

Register custom authentication handlers for HTTP requests. Returns: Iterable[CondaAuthHandler] Example:
import os
from conda import plugins
from requests.auth import AuthBase


class EnvironmentHeaderAuth(AuthBase):
    def __init__(self, *args, **kwargs):
        self.username = os.environ["EXAMPLE_CONDA_AUTH_USERNAME"]
        self.password = os.environ["EXAMPLE_CONDA_AUTH_PASSWORD"]

    def __call__(self, request):
        request.headers["X-Username"] = self.username
        request.headers["X-Password"] = self.password
        return request


@plugins.hookimpl
def conda_auth_handlers():
    yield plugins.types.CondaAuthHandler(
        name="environment-header-auth",
        handler=EnvironmentHeaderAuth,
    )
  • Handler must be a subclass of requests.auth.AuthBase
  • Used for authenticating requests to channels
  • Can be channel-specific

conda_health_checks

Register health checks for conda doctor command. Returns: Iterable[CondaHealthCheck] Example (Check Only):
from conda import plugins


def example_health_check(prefix: str, verbose: bool):
    print("This is an example health check!")


@plugins.hookimpl
def conda_health_checks():
    yield plugins.types.CondaHealthCheck(
        name="example-health-check",
        action=example_health_check,
    )
Example (Check with Fix):
from conda import plugins


def my_health_check(prefix: str, verbose: bool):
    # Check and report issues
    print("Checking for issues...")


def my_health_fix(prefix: str, args) -> int:
    # Fix the issues
    print("Fixing issues...")
    return 0  # exit code


@plugins.hookimpl
def conda_health_checks():
    yield plugins.types.CondaHealthCheck(
        name="my-check",
        action=my_health_check,
        fixer=my_health_fix,
        summary="Check for common issues",
        fix="Repair detected issues",
    )
  • Health checks diagnose problems in conda environments
  • Optional fixer callable can repair detected issues
  • Invoked via conda doctor or conda doctor --fix

conda_pre_transaction_actions

Register pre-transaction hooks that run before all other actions in an UnlinkLinkTransaction. Returns: Iterable[CondaPreTransactionAction] Example:
from conda import plugins
from conda.plugins.types import CondaPreTransactionAction
from conda.core.path_actions import Action


class PrintAction(Action):
    def verify(self):
        print("Performing verification...")
        self._verified = True

    def execute(self):
        print(
            self.transaction_context,
            self.target_prefix,
            self.unlink_precs,
            self.link_precs,
            self.remove_specs,
            self.update_specs,
            self.neutered_specs,
        )

    def reverse(self):
        print("Reversing only happens when `execute` raises an exception.")

    def cleanup(self):
        print("Carrying out cleanup...")


class PrintActionPlugin:
    @plugins.hookimpl
    def conda_pre_transaction_actions(self) -> Iterable[CondaPreTransactionAction]:
        yield CondaPreTransactionAction(
            name="example-pre-transaction-action",
            action=PrintAction,
        )
  • Must subclass conda.core.path_actions.Action
  • Implement verify(), execute(), reverse(), and cleanup() methods
  • Runs before package unlinking/linking operations

conda_post_transaction_actions

Register post-transaction hooks that run after all other actions in an UnlinkLinkTransaction. Returns: Iterable[CondaPostTransactionAction] Example:
from conda import plugins
from conda.plugins.types import CondaPostTransactionAction
from conda.core.path_actions import Action


class PrintAction(Action):
    def verify(self):
        print("Performing verification...")
        self._verified = True

    def execute(self):
        print(
            self.transaction_context,
            self.target_prefix,
            self.unlink_precs,
            self.link_precs,
            self.remove_specs,
            self.update_specs,
            self.neutered_specs,
        )

    def reverse(self):
        print("Reversing only happens when `execute` raises an exception.")

    def cleanup(self):
        print("Carrying out cleanup...")


class PrintActionPlugin:
    @plugins.hookimpl
    def conda_post_transaction_actions(self) -> Iterable[CondaPostTransactionAction]:
        yield CondaPostTransactionAction(
            name="example-post-transaction-action",
            action=PrintAction,
        )
  • Runs after all package operations complete
  • Same action interface as pre-transaction actions
  • Useful for post-installation tasks

conda_pre_solves

Register pre-solve functions that run before the solver processes package specs. Returns: Iterable[CondaPreSolve] Example:
from conda import plugins
from conda.models.match_spec import MatchSpec


def example_pre_solve(
    specs_to_add: frozenset[MatchSpec],
    specs_to_remove: frozenset[MatchSpec],
):
    print(f"Adding {len(specs_to_add)} packages")
    print(f"Removing {len(specs_to_remove)} packages")


@plugins.hookimpl
def conda_pre_solves():
    yield plugins.types.CondaPreSolve(
        name="example-pre-solve",
        action=example_pre_solve,
    )
  • Receives specs to be added and removed
  • Useful for logging, validation, or analytics
  • Cannot modify the specs (read-only access)

conda_post_solves

Register post-solve functions that run after the solver provides package records. Returns: Iterable[CondaPostSolve] Example:
from conda import plugins
from conda.models.records import PackageRecord


def example_post_solve(
    repodata_fn: str,
    unlink_precs: tuple[PackageRecord, ...],
    link_precs: tuple[PackageRecord, ...],
):
    print(f"Uninstalling {len(unlink_precs)} packages")
    print(f"Installing {len(link_precs)} packages")


@plugins.hookimpl
def conda_post_solves():
    yield plugins.types.CondaPostSolve(
        name="example-post-solve",
        action=example_post_solve,
    )
  • Receives the solve result with packages to unlink/link
  • repodata_fn indicates which repodata file was used
  • Useful for reporting or analytics on solve results

conda_settings

Register new configuration settings. Returns: Iterable[CondaSetting] Example:
from conda import plugins
from conda.common.configuration import PrimitiveParameter


@plugins.hookimpl
def conda_settings():
    yield plugins.types.CondaSetting(
        name="example_option",
        description="This is an example option",
        parameter=PrimitiveParameter("default_value", element_type=str),
        aliases=("example_option_alias",),
    )
  • Settings appear in .condarc configuration files
  • Use PrimitiveParameter for simple types or SequenceParameter for lists
  • Can define aliases for backward compatibility

conda_reporter_backends

Register custom reporter backends for output formatting. Returns: Iterable[CondaReporterBackend] Example:
from pprint import pformat
from conda import plugins
from conda.plugins.types import (
    CondaReporterBackend,
    ReporterRendererBase,
    ProgressBarBase,
)


class PprintReporterRenderer(ReporterRendererBase):
    "Implementation of the ReporterRendererBase"

    def detail_view(self, data):
        return pformat(data)

    def envs_list(self, data):
        formatted_data = pformat(data)
        return f"Environments: {formatted_data}"

    def progress_bar(self, description, io_context_manager) -> ProgressBarBase:
        "Returns our custom progress bar implementation"
        return PprintProgressBar(description, io_context_manager)


class PprintProgressBar(ProgressBarBase):
    "Blank implementation of ProgressBarBase which does nothing"

    def update_to(self, fraction) -> None:
        pass

    def refresh(self) -> None:
        pass

    def close(self) -> None:
        pass


@plugins.hookimpl
def conda_reporter_backends():
    yield CondaReporterBackend(
        name="pprint",
        description="Reporter backend based on the pprint module",
        renderer=PprintReporterRenderer,
    )
  • Controls how conda formats output
  • Must implement ReporterRendererBase interface
  • Can customize progress bars, spinners, and prompts

conda_session_headers

Register HTTP request headers for all requests to specific hosts. Returns: Iterable[CondaRequestHeader] Parameters:
  • host (str): The hostname for the request
Example:
from conda import plugins

HOSTS = {"example.com", "sub.example.com"}


@plugins.hookimpl
def conda_session_headers(host: str):
    if host in HOSTS:
        yield plugins.types.CondaRequestHeader(
            name="Example-Header",
            value="example",
        )
  • Headers are added to all requests to the specified host
  • Useful for API keys, authentication tokens, or vendor-specific headers
  • Can register multiple headers

conda_request_headers

Register HTTP request headers for specific paths on specific hosts. Returns: Iterable[CondaRequestHeader] Parameters:
  • host (str): The hostname for the request
  • path (str): The path for the request
Example:
from conda import plugins

HOSTS = {"example.com", "sub.example.com"}
ENDPOINT = "/path/to/endpoint.json"


@plugins.hookimpl
def conda_request_headers(host: str, path: str):
    if host in HOSTS and path == ENDPOINT:
        yield plugins.types.CondaRequestHeader(
            name="Example-Header",
            value="example",
        )
  • More granular than session headers (specific to host + path)
  • Useful for endpoint-specific authentication or tracking

conda_prefix_data_loaders

Register custom loaders to expose non-conda packages as conda packages. Returns: Iterable[CondaPrefixDataLoader] Example:
from pathlib import Path
from conda import plugins
from conda.common.path import PathType
from conda.models.records import PrefixRecord
from conda.plugins.types import CondaPrefixDataLoader


@plugins.hookimpl
def conda_prefix_data_loaders():
    yield CondaPrefixDataLoader(
        "hypothetical",
        load_hypothetical_packages,
    )


def load_hypothetical_packages(
    prefix: PathType, records: dict[str, PrefixRecord]
) -> dict[str, PrefixRecord]:
    penguin_records = {}
    for info in Path(prefix).glob("lib/penguin/*.penguin-info"):
        name, version = info.name.rsplit("-", 1)
        kwargs = {}  # retrieve extra fields here
        penguin_records[name] = PrefixRecord(
            name=name, version=version, build_number=0, build="0", **kwargs
        )
    records.update(penguin_records)
    return penguin_records
  • Allows conda to see packages installed by other tools
  • Updates the records dictionary in-place
  • Returns the newly loaded records

conda_environment_specifiers

EXPERIMENTAL - This API may change in future releases.
Register custom environment specification formats. Returns: Iterable[CondaEnvironmentSpecifier] Example:
import json
import random
import os
from pathlib import Path
from conda import plugins
from conda.plugins.types import EnvironmentSpecBase
from conda.env.env import Environment

packages = ["python", "numpy", "scipy", "matplotlib", "pandas", "scikit-learn"]


class RandomSpec(EnvironmentSpecBase):
    extensions = {".random"}

    def __init__(self, filename: str):
        self.filename = filename

    def can_handle(self):
        # Return early if no filename was provided
        if self.filename is None:
            return False

        # Extract the file extension (e.g., '.txt' or '' if no extension)
        file_ext = os.path.splitext(self.filename)[1]

        # Check if the file has a supported extension and exists
        return any(
            spec_ext == file_ext and os.path.exists(self.filename)
            for spec_ext in RandomSpec.extensions
        )

    def env(self):
        return Environment(
            name="".join(random.choice("0123456789abcdef") for i in range(6)),
            dependencies=[random.choice(packages) for i in range(6)],
        )


@plugins.hookimpl
def conda_environment_specifiers():
    yield plugins.types.CondaEnvironmentSpecifier(
        name="random",
        environment_spec=RandomSpec,
    )
  • Parse custom environment file formats
  • Must implement can_handle() and env property
  • can_handle() determines if the plugin can parse the file
  • env property returns a conda.env.env.Environment object

conda_environment_exporters

Register custom environment export formats. Returns: Iterable[CondaEnvironmentExporter] Example:
import tomlkit
from conda import plugins
from conda.exceptions import CondaValueError
from conda.models.environment import Environment
from conda.plugins.types import CondaEnvironmentExporter


def export_toml(env: Environment) -> str:
    # Export Environment to TOML format
    # For formats that use the standard dictionary structure,
    # you can use the shared utility:
    from conda.plugins.environment_exporters.standard import to_dict

    env_dict = to_dict(env)

    # Create TOML document
    toml_doc = tomlkit.document()

    if env_dict.get("name"):
        toml_doc["name"] = env_dict["name"]

    if env_dict.get("channels"):
        toml_doc["channels"] = env_dict["channels"]

    if env_dict.get("dependencies"):
        toml_doc["dependencies"] = env_dict["dependencies"]

    if env_dict.get("variables"):
        toml_doc["variables"] = env_dict["variables"]

    return tomlkit.dumps(toml_doc)


@plugins.hookimpl
def conda_environment_exporters():
    yield CondaEnvironmentExporter(
        name="environment-toml",
        aliases=("toml",),
        default_filenames=("environment.toml",),
        export=export_toml,
    )
  • Export environments to custom formats (JSON, TOML, XML, etc.)
  • Used by conda export command
  • Can define aliases and default filenames
  • Must provide either export or multiplatform_export (not both)

conda_package_extractors

Register package extractors for different archive formats. Returns: Iterable[CondaPackageExtractor] Example:
from conda import plugins
from conda.common.path import PathType


def extract_custom(source_path: PathType, destination_directory: PathType) -> None:
    # Custom extraction logic for a hypothetical package format
    ...


@plugins.hookimpl
def conda_package_extractors():
    yield plugins.types.CondaPackageExtractor(
        name="custom-package",
        extensions=[".custom"],
        extract=extract_custom,
    )
  • Handle unpacking of package archives
  • Each extractor specifies supported file extensions
  • Extraction function receives source path and destination directory
  • Extensions are matched case-insensitively

Decorator Reference

@plugins.hookimpl

The hookimpl decorator marks a function as a plugin hook implementation.
from conda import plugins

@plugins.hookimpl
def conda_subcommands():
    yield plugins.types.CondaSubcommand(...)
The function name must match the hook specification name (e.g., conda_solvers, conda_subcommands, etc.).

Plugin Overview

Learn about the plugin system architecture

Plugin Types

Explore all plugin type definitions