Repository F# setup
open System
open System.IO
open System.Threading
open System.Threading.Tasks
open Axial
open Axial.Layers
open Axial.Console
open Axial.FileSystem
open Axial.Hosting
open Axial.Hosting.Browser
open Axial.Hosting.Node
open Axial.HttpClient
open Axial.PlatformService
open Axial.Process
open Axial.State
open Axial.Telemetry
open Axial.Telemetry.JavaScript

Axial integrates seamlessly with ordinary .NET code — nothing stops a workflow from calling File.ReadAllText or new HttpClient() directly. The built-in services exist for the capabilities most applications reach for often enough to be worth wrapping: the clock and other operational services, the console, the file system, external processes, and HTTP. Each one is an ordinary explicit dependency. Nothing here is a new mechanism — these pages apply service contracts and layers to capabilities the library already wrote for you.

Every built-in service is built in two layers:

  1. A direct wrap. The service contract mirrors the .NET API it replaces — IClock.UtcNow(), FileSystem.readAllText, Process.command — so nothing you already know about the underlying capability stops applying. Wrapping it, rather than calling it ambiently, is what earns three things for free: a typed error channel in place of unclassified exceptions, concurrency handling through the Flow runtime instead of raw tasks, and a mockable dependency — every service ships a deterministic test double beside its live implementation, and the platform services also compose into BaseRuntime as one bundle.
  2. An improved ergonomic API, where it earns its place. Some services stop at the wrap — Console and Clock are thin enough that the .NET API was already the right shape. Others add real value on top: FileSystem and HttpClient replace a dozen exception types with one typed union each; EnvironmentVariable adds required, parsed reads over the raw string lookup; Process adds composable piping and secret redaction that System.Diagnostics.Process has no equivalent for.
Service Wraps Ergonomic layer on top
Clock DateTimeOffset.UtcNow Derived readers (utcDateTime, unixTimeSeconds, unixTimeMilliseconds)
Logging An ambient logger logException preserves the exception object instead of flattening it to a string; live defaults to a safe no-op
Randomness and GUIDs System.Random, Guid.NewGuid() nextInt min max bounds a value in one call; Random.bytes count allocates and fills in one step
Environment variables Environment.GetEnvironmentVariable EnvironmentVariable module: required, parsed reads failing with EnvironmentVariableError instead of null or an exception
Console System.Console None — the wrap is the whole surface; failures are defects, not a typed channel
FileSystem System.IO.File / Directory Every operation returns FileSystemError in place of a dozen exception types
Processes System.Diagnostics.Process Composable piping, secretArg redaction, a DSL, typed timeouts and transcripts
HTTP HttpClient DSL builders with automatic URL-encoding, typed HttpError, per-request timeout, retryTransient with backoff
open Axial
open Axial.Console
Every built-in service follows the same three-part shape:
Part Purpose
IHasClock, IHasConsole, IHasFileSystem, IHasProcess, IHasHttp The contract a workflow constrains its environment with
Console.live, FileSystem.live, Http.live The implementation backed by the real platform
Layer.succeed Console.live, Layer.succeed FileSystem.live, Layer.succeed (Http.live …) The same implementation as a Layer for runtime composition

A workflow names the contract and never the implementation:

let greet name : Flow<#IHasConsole, Never, unit> =
    Console.writeLine $"Hello, {name}."
The host supplies `live` at the edge, and tests supply a recording or in-memory value implementing the same interface. Because the requirement is in the type, neither one can be forgotten.

When to declare your own instead

Use these services when you genuinely need the real capability. When a workflow only needs "somewhere to report progress" or "the current configuration", declare a narrow application dependency instead — see choosing an approach. Depending on IConsole to print one line couples the workflow to a terminal it may not have.

In this section

  1. Platform services — clock, logging, randomness, GUIDs, and environment variables.
  2. Console — standard streams, redirection, and terminal control.
  3. FileSystem — files, directories, paths, and typed FileSystemError values.
  4. Processes — external commands as composable, typed workflows.
  5. HTTP — typed requests, decoded responses, and transient-failure retries.
  6. Tutorial: Composing built-in services — embedding BaseRuntime and your own dependencies in one environment.

Two related capabilities are documented elsewhere because they are not services in this sense. Telemetry is cross-cutting instrumentation of the runtime rather than a dependency a workflow declares, and hosting supplies environments instead of being one.