How to Configure the HTTP Client and Custom TLS Settings in Forge

Forge employs a three-layer architecture built on reqwest that separates HTTP configuration into domain models, configuration files, and infrastructure builders, enabling granular TLS control via code, TOML, or environment variables.

Forge is an AI-powered coding assistant developed in the antinomyhq/forgecode repository. Its HTTP client configuration architecture allows developers to customize connection behavior, timeouts, and TLS settings through a type-safe domain model that bridges user configuration with the underlying reqwest client.

HTTP Client Architecture Overview

Forge organizes HTTP client configuration into three distinct layers that separate data definitions from implementation details. This architecture ensures that TLS settings, timeouts, and connection pooling can be specified declaratively while the actual reqwest::Client instantiation remains encapsulated in the infrastructure layer.

Domain Layer: HttpConfig

The foundational data structures reside in forge_domain::HttpConfig, which defines every tunable HTTP option including timeouts, connection pools, redirects, DNS settings, and TLS parameters. This pure data model contains fields for TLS backend selection, version constraints, and certificate validation.

Located in crates/forge_domain/src/http_config.rs, this struct includes TlsVersion and TlsBackend enums that map directly to reqwest types through conversion functions. The domain layer contains no networking logic, serving only as the canonical schema for HTTP behavior.

Configuration Layer: ForgeConfig

The configuration crate aggregates user preferences through forge_config::ForgeConfig, which holds an optional http: Option<HttpConfig> field. This layer handles deserialization from TOML/YAML files and environment variables using the FORGE_HTTP_* prefix pattern.

In crates/forge_config/src/config.rs, the configuration parser merges file-based settings with environment overrides, producing a resolved HttpConfig that propagates to the infrastructure layer. This separation allows operators to configure TLS settings without modifying application code.

Infrastructure Layer: ForgeHttpInfra

The concrete HTTP client materializes in crates/forge_infra/src/http.rs within ForgeHttpInfra::new. This function accepts a ForgeConfig, extracts the HttpConfig (falling back to defaults if absent), and constructs a reqwest::Client through the builder pattern.

Key translation steps include:

  • Mapping TlsVersion to reqwest::tls::Version via to_reqwest_tls
  • Selecting the TLS backend through client.use_rustls_tls() when tls_backend == TlsBackend::Rustls
  • Loading custom root certificates from root_cert_paths using Certificate::from_pem or from_der
  • Enabling danger_accept_invalid_certs(true) when the accept_invalid_certs flag is set

Configuring Custom TLS Settings

Forge exposes comprehensive TLS customization through the HttpConfig struct, configurable via three interfaces: programmatic Rust construction, TOML configuration files, or environment variables.

Available TLS Options

Field Type Description Environment Variable
tls_backend TlsBackend Selects the TLS implementation (Default for platform native, Rustls for pure Rust) FORGE_HTTP_TLS_BACKEND
min_tls_version Option<TlsVersion> Minimum allowed protocol version (e.g., 1.2) FORGE_HTTP_MIN_TLS_VERSION
max_tls_version Option<TlsVersion> Maximum allowed protocol version (e.g., 1.3) FORGE_HTTP_MAX_TLS_VERSION
accept_invalid_certs bool Dangerous - bypasses certificate validation (testing only) FORGE_HTTP_ACCEPT_INVALID_CERTS
root_cert_paths Option<Vec<PathBuf>> Additional PEM/DER files to trust beyond system store FORGE_HTTP_ROOT_CERT_PATHS (comma-separated)

When ForgeHttpInfra instantiates the client, these values translate directly to reqwest::ClientBuilder method calls:

if let Some(v) = http.min_tls_version {
    client = client.min_tls_version(to_reqwest_tls(v));
}
if let Some(v) = http.max_tls_version {
    client = client.max_tls_version(to_reqwest_tls(v));
}
match http.tls_backend {
    TlsBackend::Rustls => client = client.use_rustls_tls(),
    TlsBackend::Default => {} // platform default
}
if http.accept_invalid_certs {
    client = client.danger_accept_invalid_certs(true);
}
if let Some(paths) = http.root_cert_paths {
    for p in paths { /* read PEM/DER and add_root_certificate */ }
}

Method 1: Programmatic Configuration

Construct HttpConfig directly in Rust for compile-time safety:

use forge_domain::{HttpConfig, TlsVersion, TlsBackend};

let http_cfg = HttpConfig {
    // Timeouts (seconds)
    connect_timeout: 20,
    read_timeout: 300,
    // TLS customization
    tls_backend: TlsBackend::Rustls,
    min_tls_version: Some(TlsVersion::V1_2),
    max_tls_version: Some(TlsVersion::V1_3),
    accept_invalid_certs: false,
    root_cert_paths: Some(vec![
        "/etc/ssl/custom-ca.pem".into(),
        "/home/user/mycert.der".into(),
    ]),
    ..HttpConfig::default()
};

Method 2: TOML Configuration File

Define settings in a configuration file that forge_config loads at runtime:


# config.toml

[http]
connectTimeout = 20
readTimeout = 300
tlsBackend = "rustls"
minTlsVersion = "1.2"
maxTlsVersion = "1.3"
acceptInvalidCerts = false
rootCertPaths = "/etc/ssl/custom-ca.pem,/home/user/mycert.der"

Load the configuration using forge_config::ForgeConfig::from_path("config.toml"). The http section maps directly onto the HttpConfig struct fields.

Method 3: Environment Variables

Override or define settings without touching configuration files:

export FORGE_HTTP_TLS_BACKEND=rustls
export FORGE_HTTP_MIN_TLS_VERSION=1.2
export FORGE_HTTP_MAX_TLS_VERSION=1.3
export FORGE_HTTP_ROOT_CERT_PATHS="/etc/ssl/custom-ca.pem,/home/user/mycert.der"
export FORGE_HTTP_ACCEPT_INVALID_CERTS=false

Complete Application Example

Integrate the configuration into a running application:

use forge_infra::http::ForgeHttpInfra;
use forge_app::FileWriterInfra;
use std::sync::Arc;

async fn run(http_cfg: HttpConfig) -> anyhow::Result<()> {
    // Wrap the config in the top-level ForgeConfig
    let forge_cfg = forge_config::ForgeConfig {
        http: Some(http_cfg),
        ..Default::default()
    };

    // Provide a concrete FileWriterInfra implementation
    let file_writer: Arc<dyn FileWriterInfra> = Arc::new(forge_infra::fs_write::FsWriteInfra::default());

    // Build the HTTP infra with custom TLS settings
    let http = ForgeHttpInfra::new(forge_cfg, file_writer);

    // Execute request using configured client
    let url = reqwest::Url::parse("https://api.example.com/health")?;
    let resp = http.http_get(&url, None).await?;
    println!("Status: {}", resp.status());
    Ok(())
}

Summary

  • Three-layer architecture: Forge separates HTTP concerns into HttpConfig (domain), ForgeConfig (serialization), and ForgeHttpInfra (implementation) to maintain clean boundaries between data and networking logic.
  • Source locations: Domain models live in crates/forge_domain/src/http_config.rs, configuration aggregation in crates/forge_config/src/config.rs, and the reqwest::Client builder in crates/forge_infra/src/http.rs.
  • TLS flexibility: Choose between Rustls and native TLS backends, constrain protocol versions to TLS 1.2 or 1.3, mount custom certificate authorities, and control certificate validation.
  • Configuration interfaces: Set TLS parameters via Rust code, TOML files, or FORGE_HTTP_* environment variables, with the infrastructure layer automatically applying them to the underlying reqwest client.

Frequently Asked Questions

What TLS backends does Forge support?

Forge supports two TLS backends configured through the tls_backend field in HttpConfig. Setting TlsBackend::Rustls forces the pure Rust Rustls implementation via client.use_rustls_tls(), while TlsBackend::Default uses the platform's native TLS library (typically OpenSSL on Linux, Secure Transport on macOS, or Schannel on Windows).

How do I bypass certificate validation for local testing?

Set accept_invalid_certs: true in your HttpConfig or export FORGE_HTTP_ACCEPT_INVALID_CERTS=true. This calls reqwest::ClientBuilder::danger_accept_invalid_certs(true), which disables all certificate validation. Only use this in development environments, as it exposes connections to man-in-the-middle attacks.

Can I configure all HTTP settings through environment variables?

Yes. The forge_config crate automatically maps environment variables with the FORGE_HTTP_* prefix to HttpConfig fields. For example, FORGE_HTTP_TLS_BACKEND=rustls sets the backend, while FORGE_HTTP_ROOT_CERT_PATHS accepts comma-separated paths to PEM or DER certificate files that augment the system's trust store.

Where does Forge actually create the HTTP client?

The concrete reqwest::Client instantiation occurs in crates/forge_infra/src/http.rs within the ForgeHttpInfra::new function. This method extracts HttpConfig from the provided ForgeConfig and translates the domain model into reqwest::ClientBuilder calls, handling TLS version mapping, backend selection, and certificate loading before producing the final client instance.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →