Skip to content

Integrations & Hardware ​

Modern applications do not exist in a vacuum. They need to process payments through Stripe, send SMS messages via Twilio, or read physical temperature data from an I2C hardware sensor.

However, external integrations are where AI-generated code is most dangerous. If an AI has unrestricted internet access, a hallucination could leak data to an unauthorized endpoint or spam a paid API.

Carotene solves this by enforcing Hexagonal Architecture. The AI-generated core domain is completely isolated. It cannot make raw fetch() calls. Every connection to the outside world must be explicitly declared as an integration.

The Integration Primitive ​

The integration block treats third-party software APIs and physical hardware devices exactly the same: as black-box services that take inputs and yield outputs.

Typed Configs (No Guesswork) ​

You configure integrations using Typed config Blocks. Because the block is typed, the Carotene compiler strictly validates that you have provided the required parameters for that specific protocol.

1. Software APIs (REST / OpenAPI) ​

When integrating with a web service, you use protocols like openapi or rest. To enforce strict security boundaries and prevent secret leakage, integrations must be defined inside the specific execution block (backend or frontend) that uses them.

dart
domain Commerce {
  
  backend PaymentService {
    // The integration is strictly scoped to this backend. 
    // The frontend cannot access it.
    integration Stripe {
      config openapi {
        url: "https://api.stripe.com/v1"
        auth: "env.STRIPE_SECRET_KEY" // Secret keys are safe here
      }

      function CreateCharge(amount: Float) -> Future<String>
    }

    function Checkout() {
      // The AI is allowed to call the scoped integration
      calls integration.Stripe.CreateCharge
    }
  }
  
  frontend WebStore {
    // A completely separate integration specifically for the client
    integration StripeElements {
      config sdk { auth: "env.STRIPE_PUBLIC_KEY" }
      function TokenizeCard(element: UIElement) -> Future<String>
    }
  }
}

The Sandbox Guarantee: If the AI implements a frontend view and tries to call the backend's CreateCharge integration, the compiler instantly fails the build. The runtime sandbox physically blocks the client from accessing secret-bound integrations.

Auto-Generation from Open Standards ​

Writing out integration functions for massive third-party APIs by hand defeats the purpose of rapid generation. Carotene acts as your excavator here, too.

You do not need to manually define every endpoint. You can point the Carotene CLI at any OpenAPI, Swagger, or AsyncAPI specification file.

bash
# Automatically converts a Swagger file into a Carotene integration block
carotene import openapi stripe-spec.json --name Stripe

The CLI will read the open standard and automatically generate the .carrot integration block, complete with perfectly typed models, inputs, and function signatures. It brings the wild west of third-party APIs safely under Carotene's strict compile-time guardrails in seconds.

2. Hardware & IoT (Edge Compute) ​

Carotene is not just for web apps. If your target is an edge device (e.g., a Raspberry Pi running a generated Rust binary), you treat hardware exactly like a software API, scoped to your firmware execution block.

dart
domain SmartThermostat {

  backend Firmware {
    config rust { target: "aarch64-unknown-linux-gnu" }

    integration TemperatureSensor {
      // The compiler strictly validates I2C hardware properties
      config i2c { 
        address: "0x76"
        pins: [4, 5] 
      }
      
      function ReadContinuous() -> Stream<Float>
    }
    
    loop MonitorTemp {
      // Subscribing to a hardware stream is identical to a WebSocket stream
      observes integration.TemperatureSensor.ReadContinuous
    }
  }
}

Secure Secrets Management (env) ​

Integrations require API keys, but handing production secrets to an AI coding agent is a massive security risk.

Carotene bans the use of untyped process.env calls. Instead, you declare your secrets in the top-level env block. The framework generates a strictly typed dependency-injection context.

dart
// Define the required environment variables
env {
  STRIPE_SECRET_KEY: String { secret: true }
  TWILIO_SID: String { secret: true }
}

When the AI agent generates the implementation, Carotene injects mock keys (e.g., sk_test_mock_carotene_xxx) into the local sandbox environment. The AI can write and test the integration logic perfectly, but it never sees or touches your production keys. The real keys are only injected by your CI/CD pipeline during deployment.

Mock-Driven Development ​

To allow the AI to write and test code rapidly without hitting live APIs (and incurring costs or rate limits), you can define mock responses directly inside the integration.

dart
integration Stripe {
  config openapi { url: "https://api.stripe.com/v1" }

  function CreateCharge(amount: Float) -> Future<String> {
    // The AI's tests will run against this deterministic mock data
    mocks {
      returns: "ch_mock_success_123"
    }
  }
}

During the AI's autonomous TDD (Test-Driven Development) loop, the compiler intercepts the callsverb and returns the mock data. Only when you explicitly flag a build for production does the framework compile the real network adapter.