Topology
Topology Is Runtime Truth
Sigil topology is the canonical, compiler-visible declaration of a project's external runtime dependencies.
Topology is not config.
Topology answers:
- what external things this project depends on
- what those logical dependencies are called
- which environment names exist
Config answers:
- how one named environment constructs the runtime world for those dependencies
Why Sigil Splits Topology from Config
Without this split, runtime truth gets blurred together:
- architecture and credentials live in one file
- app code falls back to
process.env - tools reconstruct the system from strings
Sigil prefers one explicit model:
src/topology.lib.sigildeclares dependency handles and environment namesconfig/exports the selected environment's.lib.sigil world- application code uses typed handles from
•topology - only config modules may read
process.env
Canonical Project Shape
Topology-aware projects define:
src/topology.lib.sigil
config/local.lib.sigil
config/test.lib.sigil
config/production.lib.sigil
Environment names are flexible, but the file path is canonical:
- if Sigil is run with
--env test, the project needsconfig/test.lib.sigil - if Sigil is run with
--env production, the project needsconfig/production.lib.sigil
Canonical Topology Module
src/topology.lib.sigil declares only dependency handles and environment names:
c local=(§topology.environment("local"):§topology.Environment)
c mailerApi=(§topology.httpService("mailerApi"):§topology.HttpServiceDependency)
c prod=(§topology.environment("prod"):§topology.Environment)
c test=(§topology.environment("test"):§topology.Environment)
No URLs. No ports. No usernames. No passwords. No env-var names.
Those belong in config.
Canonical Config Modules
Each declared environment gets one config module exporting world:
c world=(†runtime.world(†clock.systemClock(),†fs.real(),[†http.proxy("http://127.0.0.1:45110",•topology.mailerApi)],†log.capture(),†process.deny(),†random.seeded(1337),[],†timer.virtual()):†runtime.World)
Production-style config can read env vars, but only there:
e process
c world=(†runtime.world(†clock.systemClock(),†fs.real(),[†http.proxy((process.env.mailerApiUrl:String),•topology.mailerApi)],†log.stdout(),†process.real(),†random.real(),[],†timer.real()):†runtime.World)
Application Code Uses Handles, Not Endpoints
Canonical HTTP usage:
λmain()=>!Http String match §httpClient.get(•topology.mailerApi,§httpClient.emptyHeaders(),"/health"){
Ok(response)=>response.body|
Err(error)=>error.message
}
Canonical TCP usage:
λmain()=>!Tcp String match §tcpClient.send(•topology.eventStream,"ping"){
Ok(response)=>response.message|
Err(error)=>error.message
}
Forbidden patterns:
§httpClient.get("http://127.0.0.1:45110",headers,"/health")
§tcpClient.send("127.0.0.1","ping",45120)
process.env.mailerApiUrl
--env Is Required
Sigil does not guess a default environment for topology-aware work.
Use:
sigil validate projects/topology-http --env test
sigil run projects/topology-http/src/getClient.sigil --env test
sigil test projects/topology-http/tests --env test
If topology is present and --env is missing, Sigil rejects the command.
What Sigil Enforces
Compile-time:
- topology constructors only in
src/topology.lib.sigil - world HTTP/TCP entry constructors only in
config/*.lib.sigiland test-localworld { ... } - topology-aware HTTP/TCP APIs require dependency handles
- raw endpoint usage is rejected
process.envis only allowed inconfig/*.lib.sigil
Validate-time:
- the selected environment must be declared in topology
config/must exist.lib.sigil - the config module must export
world worldmust include every primitive effect entry- every declared HTTP/TCP dependency must appear exactly once in
world - no undeclared dependency handles are allowed in
world
Tests Are Environments
Tests are just another environment:
- same logical dependency identity
- different baseline world
- optional per-test
world { ... }derivation
That keeps one runtime model for:
- app code
- local development
- integration tests
- production