<!-- Sema documentation — Your First Program
     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/ -->

# Your First Program

> A ten-minute runnable walkthrough — create a Sema project, check it, run it, then add a neurosymbolic touch and re-check.

This is a ten-minute, hands-on walkthrough. You will create a Sema **project**,
statically check it, run it, then add one neurosymbolic construct and check again.
Everything here runs on the default build — no models to download.

If you have not built the toolchain yet, do [Installation](/start/installation/)
first.

## What a Sema project is

A Sema project is a directory with a `src/` folder. The entry point is
`src/main.sema`, and execution begins at its `main()` function. That is the whole
convention:

```
hello/
└── src/
    └── main.sema        # defines main()
```

A `sema.toml` manifest at the project root is optional — with no manifest you get
sensible defaults (see [Project Layout](/start/project-layout/)). We will start
without one and add it later.

## Step 1 — create the project

Make the directory and the source file:

```bash
mkdir -p hello/src
```

Now put this in `hello/src/main.sema`. It is small but real — a `struct`, a bit
of functional style (immutable bindings, a comprehension), an f-string, and a
`main` that carries the deterministic effect row `!{}`:

```sema
"""A first Sema program — greet a few users, deterministically."""

struct User:
    name: str
    admin: bool

def greeting(u: User) -> str !{}:
    role = "admin" if u.admin else "member"
    return f"Hello, {u.name} ({role})!"

def main() -> str !{}:
    users = [
        User(name="Ada", admin=True),
        User(name="Grace", admin=False),
        User(name="Linus", admin=False),
    ]
    lines = [greeting(u) for u in users]
    out = "\n".join(lines)
    print(out)
    return out
```

A few things to notice, because they are load-bearing:

- **`struct`, not `class`.** Sema has no classes and no inheritance; you model
  data with `struct` and `enum`, and shared behavior with traits.
- **`!{}` on every function.** That effect row is a *proof* that `greeting` and
  `main` perform no model calls and no I/O — the deterministic core.
- **Bindings are immutable** (`role`, `users`, `lines`, `out`). Use `mut x = …`
  when you need to rebind.
- **`if … else` is an expression** (`"admin" if u.admin else "member"`), and
  `[greeting(u) for u in users]` is a comprehension.

## Step 2 — check it

`sema check` runs the static checks — it parses, verifies arity and struct
fields, enforces the effect-row discipline, and flags any directive it does not
recognize. Run it after every edit:

```bash
sema check hello
```

A clean run reports no diagnostics. If you mistype a field name or call a function
with the wrong number of arguments, `sema check` catches it here, before anything
executes.

## Step 3 — run it

`sema run` executes `main()`:

```bash
sema run hello
```

You should see:

```
Hello, Ada (admin)!
Hello, Grace (member)!
Hello, Linus (member)!
```

:::tip[Verify strictly]
While developing, run with `SEMA_STRICT=1 sema run hello`. In strict mode any
recoverable degradation becomes a hard, typed error instead of a logged warning —
so nothing is quietly papered over. Leave it off in production, where the runtime
self-heals and surfaces warnings on stderr.
:::

## Step 4 — add a neurosymbolic touch

Now for the part that makes Sema *Sema*. `semantic.dedup` is a built-in semantic
operation: it removes near-duplicate items using calibrated similarity, not exact
string matching. On the default build it runs on the deterministic hash embedder,
so the result is reproducible.

Edit `hello/src/main.sema` to collapse a list of roughly-duplicate tags before
greeting. Add a helper and call it from `main`:

```sema
"""A first Sema program — greet a few users, then de-duplicate their interests."""

struct User:
    name: str
    admin: bool

def greeting(u: User) -> str !{}:
    role = "admin" if u.admin else "member"
    return f"Hello, {u.name} ({role})!"

def unique_tags(tags: list[str]) -> list[str] !{}:
    """Collapse near-duplicate tags via calibrated similarity."""
    return semantic.dedup(tags, 0.9)

def main() -> str !{}:
    users = [
        User(name="Ada", admin=True),
        User(name="Grace", admin=False),
        User(name="Linus", admin=False),
    ]
    lines = [greeting(u) for u in users]

    tags = ["databases", "databases", "compilers"]
    interests = unique_tags(tags)

    out = "\n".join(lines) + f"\nInterests: {interests}"
    print(out)
    return out
```

`semantic.dedup(tags, 0.9)` takes the list and a similarity threshold. The two
`"databases"` entries collapse to one, and `"compilers"` stays — so `interests`
is `["databases", "compilers"]`.

Note that `unique_tags` is still `!{}`. Semantic operations on the built-in
engine are part of the deterministic core; the effect row only gains
`model.invoke` when you cross into `simulate def` or a real model call.

## Step 5 — check and run again

```bash
sema check hello
sema run hello
```

The output now ends with:

```
Interests: ['databases', 'compilers']
```

That is the loop you will use for everything: **edit → `sema check` → `sema run`**
(with `SEMA_STRICT=1` while verifying). When you are ready to add contracts and
tests, `sema assure` grades the verification — see the toolchain page.

## Where to go next

- [Toolchain](/start/toolchain/) — every command, including `sema assure` for
  verification and `sema doc` for reflected documentation.
- [Language Overview](/language/overview/) — the full tour of types, effects,
  traits, enums, generics, and pattern matching.
- [Project Layout](/start/project-layout/) — splitting into modules, imports and
  visibility, `sema.toml`, and dependencies.
