Module: AgentHarness

Defined in:
lib/agent_harness.rb,
lib/agent_harness/errors.rb,
lib/agent_harness/version.rb,
lib/agent_harness/response.rb,
lib/agent_harness/mcp_server.rb,
lib/agent_harness/configuration.rb,
lib/agent_harness/token_tracker.rb,
lib/agent_harness/authentication.rb,
lib/agent_harness/error_taxonomy.rb,
lib/agent_harness/providers/base.rb,
lib/agent_harness/providers/aider.rb,
lib/agent_harness/providers/codex.rb,
lib/agent_harness/command_executor.rb,
lib/agent_harness/provider_runtime.rb,
lib/agent_harness/providers/cursor.rb,
lib/agent_harness/providers/gemini.rb,
lib/agent_harness/providers/adapter.rb,
lib/agent_harness/providers/kilocode.rb,
lib/agent_harness/providers/opencode.rb,
lib/agent_harness/providers/registry.rb,
lib/agent_harness/providers/anthropic.rb,
lib/agent_harness/execution_preparation.rb,
lib/agent_harness/orchestration/metrics.rb,
lib/agent_harness/provider_health_check.rb,
lib/agent_harness/providers/mistral_vibe.rb,
lib/agent_harness/docker_command_executor.rb,
lib/agent_harness/orchestration/conductor.rb,
lib/agent_harness/providers/github_copilot.rb,
lib/agent_harness/orchestration/rate_limiter.rb,
lib/agent_harness/orchestration/health_monitor.rb,
lib/agent_harness/orchestration/circuit_breaker.rb,
lib/agent_harness/orchestration/provider_manager.rb

Overview

AgentHarness provides a unified interface for CLI-based AI coding agents.

It offers:

  • Unified interface for multiple AI coding agents (Claude Code, Cursor, Gemini CLI, etc.)

  • Full orchestration layer with provider switching, circuit breakers, and health monitoring

  • Flexible configuration via YAML, Ruby DSL, or environment variables

  • Dynamic provider registration for custom provider support

  • Token usage tracking for cost and limit calculations

Examples:

Basic usage

AgentHarness.send_message("Write a hello world function", provider: :claude)

With configuration

AgentHarness.configure do |config|
  config.logger = Logger.new(STDOUT)
  config.default_provider = :cursor
end

Direct provider access

provider = AgentHarness.provider(:claude)
provider.send_message(prompt: "Hello")

Defined Under Namespace

Modules: Authentication, ErrorTaxonomy, Orchestration, Providers Classes: AuthenticationError, CallbackRegistry, CircuitBreakerConfig, CircuitOpenError, CommandExecutionError, CommandExecutor, Configuration, ConfigurationError, DockerCommandExecutor, Error, ExecutionPreparation, HealthCheckConfig, IdleTimeoutError, InvalidDurationError, McpConfigurationError, McpServer, McpTransportUnsupportedError, McpUnsupportedError, NoProvidersAvailableError, OrchestrationConfig, ProviderConfig, ProviderError, ProviderHealthCheck, ProviderNotFoundError, ProviderRuntime, ProviderUnavailableError, RateLimitConfig, RateLimitError, Response, RetryConfig, TimeoutError, TokenTracker

Constant Summary collapse

VERSION =
"0.7.1"

Class Method Summary collapse

Class Method Details

.auth_status(provider_name) ⇒ Hash

Get detailed authentication status for a provider

Parameters:

  • provider_name (Symbol)

    the provider name

Returns:

  • (Hash)

    status with :valid, :expires_at, :error keys



183
184
185
# File 'lib/agent_harness.rb', line 183

def auth_status(provider_name)
  Authentication.auth_status(provider_name)
end

.auth_url(provider_name) ⇒ String

Generate an OAuth URL for a provider

Parameters:

  • provider_name (Symbol)

    the provider name

Returns:

  • (String)

    the OAuth authorization URL

Raises:

  • (NotImplementedError)

    if provider doesn’t support OAuth



191
192
193
# File 'lib/agent_harness.rb', line 191

def auth_url(provider_name)
  Authentication.auth_url(provider_name)
end

.auth_valid?(provider_name) ⇒ Boolean

Check if authentication is valid for a provider

Parameters:

  • provider_name (Symbol)

    the provider name

Returns:

  • (Boolean)

    true if auth is valid



176
177
178
# File 'lib/agent_harness.rb', line 176

def auth_valid?(provider_name)
  Authentication.auth_valid?(provider_name)
end

.check_provider(provider_name, timeout: nil, executor: nil, provider_runtime: nil) ⇒ Hash

Check health of a single provider

Parameters:

  • provider_name (Symbol)

    the provider name

  • timeout (Integer, nil) (defaults to: nil)

    timeout in seconds (nil lets ProviderHealthCheck apply its validated default)

Returns:

  • (Hash)

    health status with :name, :status, :message, :latency_ms



227
228
229
230
231
232
233
# File 'lib/agent_harness.rb', line 227

def check_provider(provider_name, timeout: nil, executor: nil, provider_runtime: nil)
  options = {}
  options[:timeout] = timeout unless timeout.nil?
  options[:executor] = executor unless executor.nil?
  options[:provider_runtime] = provider_runtime unless provider_runtime.nil?
  ProviderHealthCheck.check(provider_name, **options)
end

.check_providers(timeout: nil, executor: nil, provider_runtime: nil) ⇒ Array<Hash>

Check health of all configured providers.

Validates each enabled provider through registration, CLI availability, authentication, provider health status, and config validation checks.

Parameters:

  • timeout (Integer) (defaults to: nil)

    timeout in seconds for each check (defaults to configured value)

Returns:

  • (Array<Hash>)

    health status for each provider

Raises:

  • (ArgumentError)

    if provider_runtime is supplied; runtime overrides are only supported by ‘check_provider` to avoid leaking one provider’s execution context into every other health check



214
215
216
217
218
219
220
221
# File 'lib/agent_harness.rb', line 214

def check_providers(timeout: nil, executor: nil, provider_runtime: nil)
  raise ArgumentError, "provider_runtime is only supported for single-provider health checks" unless provider_runtime.nil?

  options = {}
  options[:timeout] = timeout unless timeout.nil?
  options[:executor] = executor unless executor.nil?
  ProviderHealthCheck.check_all(**options)
end

.conductorOrchestration::Conductor

Returns the global conductor for orchestrated requests

Returns:



66
67
68
# File 'lib/agent_harness.rb', line 66

def conductor
  @conductor ||= Orchestration::Conductor.new(config: configuration)
end

.configurationConfiguration

Returns the global configuration instance

Returns:



33
34
35
# File 'lib/agent_harness.rb', line 33

def configuration
  @configuration ||= Configuration.new
end

.configure {|Configuration| ... } ⇒ void

This method returns an undefined value.

Configure AgentHarness with a block

Yields:



40
41
42
# File 'lib/agent_harness.rb', line 40

def configure
  yield(configuration) if block_given?
end

.install_contract(name) ⇒ Hash

Get install contract metadata for a provider

Parameters:

  • name (Symbol, String)

    the provider name

Returns:

  • (Hash)

    install contract metadata

Raises:



91
92
93
# File 'lib/agent_harness.rb', line 91

def install_contract(name)
  Providers::Registry.instance.install_contract(name)
end

.installation_contract(provider_name, **options) ⇒ Hash?

Get installation metadata for a provider CLI.

Parameters:

  • provider_name (Symbol, String)

    the provider name

  • options (Hash)

    optional target selection (for example, ‘version:`)

Returns:

  • (Hash, nil)

    installation contract

Raises:



119
120
121
# File 'lib/agent_harness.rb', line 119

def installation_contract(provider_name, **options)
  Providers::Registry.instance.installation_contract(provider_name, **options)
end

.installation_contractsHash<Symbol, Hash>

Get all provider installation contracts exposed by agent-harness.

Returns:

  • (Hash<Symbol, Hash>)

    installation contracts keyed by provider



125
126
127
# File 'lib/agent_harness.rb', line 125

def installation_contracts
  Providers::Registry.instance.installation_contracts
end

.loggerLogger?

Returns the global logger

Returns:

  • (Logger, nil)

    the configured logger



54
55
56
# File 'lib/agent_harness.rb', line 54

def logger
  configuration.logger
end

.provider(name) ⇒ Providers::Base

Get a provider instance

Parameters:

  • name (Symbol)

    the provider name

Returns:



83
84
85
# File 'lib/agent_harness.rb', line 83

def provider(name)
  conductor.provider_manager.get_provider(name)
end

.provider_install_contract(provider_name, version: nil) ⇒ Hash?

Returns install metadata for a provider CLI when the provider exposes it.

Parameters:

  • provider_name (Symbol, String)

    the provider name

  • version (String, nil) (defaults to: nil)

    optional explicit CLI version override

Returns:

  • (Hash, nil)

    installation metadata



100
101
102
# File 'lib/agent_harness.rb', line 100

def provider_install_contract(provider_name, version: nil)
  provider_installation_contract(provider_name, **(version ? {version: version} : {}))
end

.provider_installation_contract(name, **options) ⇒ Hash?

Get the installation contract for a provider CLI.

Parameters:

  • name (Symbol, String)

    the provider name

  • options (Hash)

    optional target selection (for example, ‘version:`)

Returns:

  • (Hash, nil)

    provider installation contract for the requested target

Raises:



110
111
112
# File 'lib/agent_harness.rb', line 110

def provider_installation_contract(name, **options)
  Providers::Registry.instance.installation_contract(name, **options)
end

.provider_metadata(provider_name, refresh: false) ⇒ Hash

Get consolidated metadata for a provider.

Parameters:

  • provider_name (Symbol, String)

    the provider name or alias

  • refresh (Boolean) (defaults to: false)

    when true, refresh live runtime metadata such as CLI availability instead of reusing cached values

Returns:

  • (Hash)

    provider metadata

Raises:



136
137
138
# File 'lib/agent_harness.rb', line 136

def (provider_name, refresh: false)
  Providers::Registry.instance.(provider_name, refresh: refresh)
end

.provider_metadata_catalog(refresh: false) ⇒ Hash<Symbol, Hash>

Get consolidated metadata for all registered providers.

Parameters:

  • refresh (Boolean) (defaults to: false)

    when true, refresh live runtime metadata such as CLI availability instead of reusing cached values

Returns:

  • (Hash<Symbol, Hash>)

    provider metadata keyed by canonical provider



145
146
147
# File 'lib/agent_harness.rb', line 145

def (refresh: false)
  Providers::Registry.instance.(refresh: refresh)
end

.provider_smoke_test_contract(provider_name) ⇒ Hash?

Get smoke-test metadata for a provider CLI when the provider exposes it.

Parameters:

  • provider_name (Symbol, String)

    the provider name

Returns:

  • (Hash, nil)

    smoke-test contract



153
154
155
# File 'lib/agent_harness.rb', line 153

def provider_smoke_test_contract(provider_name)
  smoke_test_contract(provider_name)
end

.refresh_auth(provider_name, token: nil) ⇒ Hash

Refresh authentication credentials for a provider

Parameters:

  • provider_name (Symbol)

    the provider name

  • token (String, nil) (defaults to: nil)

    OAuth token to store

Returns:

  • (Hash)

    result with :success key

Raises:

  • (NotImplementedError)

    if provider doesn’t support credential refresh



200
201
202
# File 'lib/agent_harness.rb', line 200

def refresh_auth(provider_name, token: nil)
  Authentication.refresh_auth(provider_name, token: token)
end

.reset!void

This method returns an undefined value.

Reset configuration to defaults (useful for testing)



46
47
48
49
50
# File 'lib/agent_harness.rb', line 46

def reset!
  @configuration = nil
  @conductor = nil
  @token_tracker = nil
end

.send_message(prompt, provider: nil, executor: nil, **options) ⇒ Response

Send a message using the orchestration layer

Parameters:

  • prompt (String)

    the prompt to send

  • provider (Symbol, nil) (defaults to: nil)

    optional provider override

  • executor (CommandExecutor, nil) (defaults to: nil)

    per-request executor override

  • options (Hash)

    additional options

Returns:

  • (Response)

    the response from the provider



76
77
78
# File 'lib/agent_harness.rb', line 76

def send_message(prompt, provider: nil, executor: nil, **options)
  conductor.send_message(prompt, provider: provider, executor: executor, **options)
end

.smoke_test_contract(provider_name) ⇒ Hash?

Get smoke-test metadata for a provider CLI.

Parameters:

  • provider_name (Symbol, String)

    the provider name

Returns:

  • (Hash, nil)

    smoke-test contract

Raises:



161
162
163
164
165
# File 'lib/agent_harness.rb', line 161

def smoke_test_contract(provider_name)
  # Explicitly raise if provider is not registered to match documentation
  raise ConfigurationError, "Unknown provider: #{provider_name}" unless Providers::Registry.instance.registered?(provider_name)
  Providers::Registry.instance.smoke_test_contract(provider_name)
end

.smoke_test_contractsHash<Symbol, Hash>

Get all provider smoke-test contracts exposed by agent-harness.

Returns:

  • (Hash<Symbol, Hash>)

    smoke-test contracts keyed by provider



169
170
171
# File 'lib/agent_harness.rb', line 169

def smoke_test_contracts
  Providers::Registry.instance.smoke_test_contracts
end

.token_trackerTokenTracker

Returns the global token tracker

Returns:



60
61
62
# File 'lib/agent_harness.rb', line 60

def token_tracker
  @token_tracker ||= TokenTracker.new
end