<!-- Sema documentation — Project Layout
     Sema is a new AI-native, neurosymbolic programming language most models
     have not been trained on. Full corpus: https://sema.49.12.246.95.sslip.io/llms-full.txt
     Install language support: https://sema.49.12.246.95.sslip.io/install-skill/ -->

# Project Layout

> How a Sema project is organized — the src/ tree, modules and imports, visibility, the sema.toml manifest, and Python and native Sema packages.

This page covers how a Sema project is organized once it grows past one file: the
`src/` layout, splitting code into modules, imports and visibility, the
`sema.toml` manifest, and adding dependencies.

## The `src/` layout

A **project** is a directory. Its Sema source lives in `src/`, and the entry point
is `src/main.sema`, whose `main()` function runs when you `sema run` the project.
A larger project just has more files under `src/`:

```
finops/
├── sema.toml            # the manifest (optional; see below)
└── src/
    ├── main.sema        # entry point: defines main()
    ├── domain.sema      # data types
    └── policies.sema    # governance
```

Each `.sema` file is one **module**. A **package** is the tree rooted at a
`sema.toml` manifest, and the manifest's `[package] name` is the import root for
every module in that tree. So if `sema.toml` declares `name = "finops"`, the file
`src/domain.sema` is the module `finops.domain`.

## Splitting into modules and importing

Import from another module with `from … import …` or `import … [as …]`. Both
resolve at compile time against the package graph — there is no runtime path
search:

```sema
from finops.domain import LedgerEntry, Money
import finops.policies as policies
```

Two rules that differ from Python and matter in practice:

- **Wildcard imports do not exist.** You name every symbol you import. This keeps
  code reviewable and lets the toolchain resolve names statically.
- **Re-export is explicit.** To surface a name your module imported as part of
  your own public API, re-export it: `pub from finops.domain import Money`.

Cyclic imports and unresolvable imports are compile errors, and two packages that
export the same root name require manifest aliasing rather than silently
shadowing each other.

## Visibility: `pub`

Declarations are **module-private by default.** Mark the public surface with `pub`
(a soft keyword). Anything without `pub` is invisible outside its own module:

```sema
pub struct ReconciliationDecision:
    matched: list[LedgerEntry]

pub def reconcile(lines: list[BankLine]) -> list[ReconciliationDecision] !{model.embed}:
    ...

def candidate_score(bank: BankLine, entry: LedgerEntry) -> f32 !{model.embed}:
    ...      # module-private: only reconcile can call this
```

Visibility is per declaration, not per file, because the **public signature** — a
`pub` declaration's full signature *including its contract clauses and effect
row* — is what the verification engine keys its caches on. A private-across-module
access is a compile error that names the missing `pub`.

:::note[Module initialization is effect-checked]
Top-level statements in a module run once, in dependency order, when the module
loads. If a module's top-level code needs effects beyond `!{}`, it must declare
them in the manifest under `[package] init_effects` — initialization cannot
smuggle in ambient authority.
:::

## The `sema.toml` manifest

`sema.toml` at the project root is **optional**: with no manifest you get all
defaults. When present, it declares the package and overrides defaults without
touching code. A minimal manifest names the package and sets an edition:

```toml
[package]
name = "finops"
edition = "2026"
version = "0.1.0"

[assurance]
default = "silver"        # module grade if a module doesn't declare its own
```

Beyond the package identity, the manifest is the single place to configure the
runtime. The most useful sections:

```toml
[engine]
seed = 12345              # deterministic seed for reproducible runs
temperature = 0.7

[models]                  # which model backs each capability — swap in your own
embed    = "my-custom-embedder"
generate = "models/qwen3-0.6b.Q4_K_M.gguf"

[semantic]
cluster_threshold = 0.9   # default threshold for semantic.cluster / semantic.dedup

[journal]                 # audit-trail preset (see governance)
level = "standard"        # off | minimal | standard | audit
```

Everything the manifest sets is also readable from a program via `config.get`,
`config.model`, and `config.temperature`, so configuration is diffable,
tool-readable, and overridable without recompiling. A missing file means all
defaults; present keys override; unspecified capabilities keep their smart
default.

:::tip[Assurance grade precedence]
The verification grade for a function is resolved most-specific-wins: the manifest
`[assurance] default` is the floor, a module-level `assure <grade>` declaration
overrides it for that module, and a per-function `@assure(<grade>)` overrides
both. See [Toolchain](/start/toolchain/) for what the grades do.
:::

## Packages and dependencies

`sema add` handles **both** ecosystems from one command, installing into a
project-local, gitignored `.sema/` directory.

**PyPI packages** install into `.sema/venv` (via `uv`, with a pip fallback),
recorded in `.sema/packages.txt`, and become immediately usable from Sema through
the Python bridge — classes and methods included, no per-package glue:

```bash
sema add numpy
sema remove numpy
sema list
```

**Native Sema packages** — a directory with a `sema-pkg.toml` (`[package] name = …`)
and its own `src/*.sema` — install from a local path or a `git+<url>` source into
`.sema/packages/<name>/`:

```bash
sema add ./greetings
sema add git+https://example.com/greetings.git
```

Installed package modules import exactly like your own (`from greetings.greet
import hello`). A project module of the same name overrides a package module,
which is how you shadow or patch a dependency locally.

### The standard library needs no installation

The `std` package ships **embedded in the compiler** — its source lives in Sema
itself — so it is available to every project with no `sema add`:

```sema
from std.belief import Belief
from std.cache import memoize
from std.document import Report, render
from std.agent_loop import loop_until
```

Because the standard library is written in Sema (not hardcoded in Rust), its
parameters and logic are inspectable and changeable in the language, and a user
module of the same stem shadows the stdlib one. See the
[Standard Library overview](/stdlib/overview/) for the full module list.

## Next

- [Toolchain](/start/toolchain/) — check, run, verify, document, and inspect a
  project.
- [Modules](/language/modules/) — the deeper reference on imports, visibility, and
  the package graph.
