Skip to main content
Custom agents are integrations developed outside Harbor’s built-in registry. They may be local work in progress or private integrations not intended for upstream. A custom agent can be either installed or external.
When adding a new agent locally or integrating one into Harbor, prefer BaseInstalledAgent. Most agent integrations follow this design. Use BaseAgent only when the agent loop must remain outside the task environment.
Choose the base class based on where the agent runs.
Extend BaseInstalledAgent when Harbor should install and run the agent CLI inside the task environment.
my_agent.py
Use exec_as_root for system packages and exec_as_agent for user-level installation and execution. Override populate_context_post_run to parse usage or trajectory data after the logs are synced.

Run a custom agent

Custom agents are not registered by name, so pass module.path:ClassName to --agent (-a). The module must be importable from the Harbor process.
Use --model (-m) if the agent takes a model, --agent-kwarg (--ak) for other constructor options, and --agent-env (--ae) for environment variables.

Custom agent example

See a complete BaseAgent implementation in the Harbor repository.

Agent auth resolution

For inference connections, accept the same model slug users pass to other agents (model lookup). Use self._parse_model_name(self.model_name) to obtain LiteLLM’s resolved provider and model ID while respecting --skip-model-parsing-and-provider-mapping. Unresolved names remain unchanged. For a LiteLLM client, pass self.model_name verbatim instead of rebuilding a slug from those parts. Handle client-specific formatting inside the adapter, and preserve native identifiers and authentication for other backends, such as Tinker. Declare the connection your runtime supports: Use agent_provider_access for the agent’s credential and endpoint input names. These are fallbacks after the selected provider’s names within each environment source.
In default_api_format_by_provider, a provider match takes precedence over "default". Use ModelApiFormat members in declarations and resolved connections. Native defaults can include formats that the adapter does not support as explicit overrides. Set supports_overriding_base_url=False if the adapter cannot apply --base-url. For an SDK, pass the resolved values directly to its constructor:
For a client that reads environment variables, also declare the variable names it reads in MODEL_CONNECTION:
Pass self.model_connection.env to the client’s execution environment. The resolver selects the credential and maps it to the declared variable. In either dictionary, additional keys can name API formats or providers. A matching API format takes precedence over a provider match, then "default". Adapter hooks can override the destination for native configuration or authentication. When no entry matches, Harbor forwards the selected value using the provider’s or selected transport’s environment variable names. Provider extra_env_names are forwarded independently, using scoped agent values before ambient values. Preserve native settings unless the corresponding common override is supplied. Declare only API formats your adapter implements, and reject unsupported formats clearly. Inspect your declaration with:
See auth resolution settings for common options and credential precedence.