Getting Started

Project layout

The recommended directory structure for Vary applications.

Single-module project

A small project or library with a flat source structure:

my-project/
├── vary.toml              # Project configuration
├── src/
│   ├── main.vary          # Entry point
│   ├── store.vary         # Core logic (pure)
│   └── service.vary       # Boundary / effectful code
├── tests/
│   └── store_test.vary    # Unit tests
├── contracts/
│   └── store.md           # Informal contracts / design notes
├── .vary/                 # Compiler state (do not commit)
└── .gitignore

src/ holds all source files. tests/ holds test files (discovery patterns are test_*.vary and *_test.vary). contracts/ is a conventional directory for design notes, not compiled. .vary/ is generated by the compiler; never commit it.

Minimal vary.toml

[project]
name = "my-project"
version = "0.1.0"

[source]
directories = ["src"]
test_directories = ["tests"]

Multi-module project

A larger application with domain separation:

market-simulator/
├── vary.toml
├── src/
│   ├── main.vary                # Entry point
│   ├── domain/                  # Pure core logic
│   │   ├── account.vary
│   │   ├── order.vary
│   │   ├── trade.vary
│   │   └── types.vary
│   ├── engine/                  # Internal algorithms
│   │   ├── book.vary
│   │   └── matching.vary
│   ├── api/                     # HTTP boundary (effectful)
│   │   ├── state.vary
│   │   ├── books.vary
│   │   └── accounts.vary
│   ├── agents/                  # Simulation agents
│   │   └── random_agent.vary
│   └── metrics/                 # Observability
│       └── scale_metrics.vary
├── tests/
│   ├── domain/
│   │   ├── account_test.vary    # Unit tests for pure core
│   │   └── order_test.vary
│   ├── engine/
│   │   └── matching_test.vary
│   ├── api/
│   │   └── books_test.vary      # Integration tests
│   └── test_e2e.vary            # End-to-end tests
├── contracts/
│   ├── order-lifecycle.md       # Domain invariants
│   └── api-surface.md           # API contract documentation
├── .vary/
└── .gitignore

Subdirectories become module prefixes in imports:

import domain.order
from domain.account import Account
from engine.matching import match_orders

Directory roles

src/: source code

All application source lives under src/ by default. Organize subdirectories by domain concern:

Directory patternPurposeEffect profile
domain/Core types and pure business logicPure, no I/O, no network
engine/Algorithms and processingPure or minimal effects
api/HTTP endpoints, service boundariesEffectful: NETWORK, IO
agents/Active components, background workersEffectful
metrics/Observability and reportingEffectful: IO
sim/Simulation orchestrationMixed

The architectural principle here is separating pure core logic from effectful boundaries.

Pure core (domain/, engine/) contains business rules, data transformations, algorithms. These functions have no side effects: they take values and return values. They are straightforward to test and safe to mutate.

Effectful boundaries (api/, agents/) talk to the network, filesystem, or external services. Keep these thin; they should delegate to pure core functions for actual logic.

This separation is not just convention. Vary's effect system tracks it:

# vary.toml: deny network effects in pure core modules
[check.effects]
deny = ["NETWORK"]

You can also use the require_pure compiler option to enforce purity in core modules.

tests/: test code

Test files live under tests/ by default. Mirror the src/ subdirectory structure:

src/domain/order.vary      →  tests/domain/order_test.vary
src/engine/matching.vary   →  tests/engine/matching_test.vary

Tests use the test DSL:

test "order total is price times quantity" {
    let order = Order(price: 100, qty: 5)
    observe order.total() == 500
}
LocationCategoryWhat to test
tests/domain/UnitPure functions, type invariants
tests/engine/UnitAlgorithm correctness
tests/api/IntegrationHTTP endpoints with mock transport
tests/ (root)End-to-endFull application flows

contracts/: design documentation

A conventional directory for domain invariants, API surface contracts, cross-module interface expectations, and design decisions. This directory is not compiled or enforced by the toolchain; it exists for human readers.

For compiler-enforced contracts, use in {} / out {} blocks on functions:

def withdraw(account: Account, amount: Int) -> Account {
    in {
        amount > 0
        account.balance >= amount
    }
    out (result) {
        old(account.balance) - amount == result.balance
    }
    return Account(balance: account.balance - amount)
}

.vary/: compiler state

Generated automatically. Contains:

PathPurpose
artifacts/Content-addressed compilation cache (SHA-256)
project.jsonDetected project environment
status.jsonLast command status
history.jsonlCommand history
runs/Test and mutation run artifacts

Add to .gitignore:

.vary/
.vary-logs/
.vary-mutation-cache-*

Configuration reference

The vary.toml file at the project root controls project layout and toolchain behaviour.

Layout options

[project]
name = "my-project"
version = "0.1.0"
edition = "1"

[source]
directories = ["src"]           # Where source files live
test_directories = ["tests"]    # Where test files live
excludes = [".vary/**"]         # Glob patterns to skip
strict_imports = false          # Require explicit imports

[build]
entry = "main.vary:main"       # Entry point (module:function)
output_dir = "build"           # Compiled output

Quality enforcement

[compiler]
strict_null_checks = true       # Enforce null safety
require_contracts = false       # Require contracts on functions
min_contract_percent = 0        # Minimum % of functions with contracts
require_pure = false            # Require pure function markers
min_pure_percent = 0            # Minimum % of pure functions

[test]
parallel = 4                    # Parallel test runners
coverage = true                 # Enable coverage tracking
coverage_threshold = 80         # Minimum coverage %

[mutation]
profile = "ci"                  # "ci" for JSON + score gate
ci_score_threshold = 80.0       # Minimum mutation score
min_observability = 75.0        # Minimum observability score

[check.effects]
deny = ["NETWORK"]              # Deny network effects in checked code

[services]
allowed_hosts = ["api.example.com"]   # Restrict outbound service calls
denied_hosts = ["*.internal.corp"]

Per-module mutation rules

[[mutation.module]]
pattern = "domain/**"
min_score = 90.0                # Pure core should have high mutation score
max_survivors = 3

[[mutation.module]]
pattern = "api/**"
min_score = 60.0                # Boundaries are harder to mutate

Choosing a layout

Project sizeLayoutNotes
Script or spikeFlat files, no subdirsvary run main.vary is enough
Small librarySingle src/ + tests/The minimal layout above
ApplicationMulti-module with domain separationMirror src/ structure in tests/
Monorepo moduleSame as application, with [dependencies] for cross-project importsUse path dependencies in vary.toml

Path dependencies for multi-project setups

# In consumer/vary.toml
[dependencies]
shared-types = { version = "1.0.0", path = "../shared-types" }
# In consumer source
from shared_types.domain import Order
← Configuration
Quick reference →