# app.osy

> The manifest at the root of every project. It names the app, says which files are model, seed, migrations and tests, and declares the capabilities the app depends on with use.

<!-- id: project-manifest · area: project · stability: stable · html: https://osysharp.com/reference/project/manifest/ -->

## Summary        {#summary}
`app.osy` is the manifest at the root of a project. It names the app, says which files play which role, and declares
the **capabilities** the app depends on. It is the first file to read in an unfamiliar project — it tells you what the
app is made of before you open a single model file.

It declares nothing ELSE: an app setting (`app.DefaultCulture = …;`) and the app's time zones and cultures
(`zones { … }`, `cultures { … }`) are declarations, and go in a model file — see [Declaring the time zones and cultures an app uses — zones { } and cultures { }](https://osysharp.com/reference/i18n/zones-and-cultures/).

## Signature      {#signature}
```osy syntax
app <Name> {
  model      "model/**/*.osy";        // entities, functions, security, UI
  seed       "seed/**/*.osy";         // data the app needs in order to exist
  migrations "migrations/**/*.migration"; // explicit schema + data migrations — NOT .osy: a migration is a
                                          // generated artefact in its own grammar, so no *.osy glob reaches one
  tests      "tests/**/*.osy";        // [Test] functions — run, never deployed

  use <Capability>;                   // a platform capability this app depends on
}
```

## Description    {#description}

### The source roles   {#roles}
Each role is a glob. They are not decoration — they decide what happens to the file:

| Role | What the files hold | What the platform does with them |
|---|---|---|
| `model` | entities, functions, security, UI | compiled and **deployed** |
| `seed` | the data the app needs to exist at all | compiled and **deployed** |
| `migrations` | explicit schema and data migrations | found here, then passed to a deploy with `--migration` — a `*.migration` is **not** compiled with your model |
| `tests` | `[Test]` functions | **run, never deployed** |

Omit a role and the conventional folder is used, so a manifest can be very short. Being explicit costs one line and
tells the next reader exactly where things live.

### A file belongs to one role   {#one-role}
Two globs can reach the same file. In a **flat project** — every `.osy` in the project root, no `model/` folder — the
obvious manifest does it to every test:

```osy title="a flat project: `*.osy` also matches `*.test.osy`" syntax
app Shop {
  model "*.osy";
  tests "*.test.osy";       // every file here is ALSO matched by the model glob above
}
```

This works, and the narrower glob wins: **where one role's files are a subset of another's, the shared files belong
to the narrower role**. Above, `checkout.test.osy` is a test and nothing else — it is not compiled into the app and
never reaches a deploy.

The rule is about which set is smaller, not about which role is called `tests`, so it reads the same way round:
`model "model.osy"; tests "*.osy";` gives `model.osy` to `model`.

When neither role's files contain the other's, there is no narrower one to prefer and the manifest is **rejected**,
naming both roles and the files. Narrow one of the globs so each file is claimed once — guessing on your behalf is
how a test quietly becomes part of the app.

### `use` declares a dependency   {#use}
`use` opts the app into a **capability** — a piece of platform surface that is not on by default, like outbound HTTP
or searchable text. It belongs in the manifest, because it is a fact about the *application*, not about one file:

```osy title="an app that makes outbound HTTP calls" test app=project-manifest
app Shop {
  model "model/**/*.osy";
  tests "tests/**/*.osy";

  use Osysharp.Http;         // now Http.Get / Http.Post exist for this app
}

string Ping(string url) {
  var r = Http.Get(url);
  return r.IsSuccess ? r.Body : "";
}
```

Without the `use`, `Http.Get` is not a thing the app can call, and the compiler says so. That is deliberate: an
application's ability to reach the outside world should be a line you can point at, not an accident of an import.

Do not confuse `use` with `using`. **`use` (manifest) declares the dependency; `using` (a file) imports its names into
that file.** A version pin belongs on the `use`. See [use](https://osysharp.com/reference/types/use/).

### A package that arrives by itself, and keeping one out   {#without}
A **bridge** — a package that completes two your app uses, like the privacy kit's holder for conversations — arrives
without a `use` line: `osy lock` finds it, pins it and prints `+ … included: completes A + B`. To keep one out, name it
with `without` in the manifest: `without Osysharp.Privacy.Conversations;`. See [Bridges — a package that arrives when an app uses the two it completes](https://osysharp.com/reference/project/bridges/).

### `tests use` — a dependency only your tests load   {#tests-use}
Some packages exist for tests: a deterministic embedder, a fake carrier, a fixed clock. Put `tests` in front of the
`use` line and the package is pinned in `osyrin.lock` like any other, loaded by `osy test`, and left out of every
other build — the app you compile and deploy does not contain it, and model code cannot reach it:

```osy title="a package for the tests alone" syntax
app Desk {
  model "model/**/*.osy";
  tests "tests/**/*.test.osy";

  use Osysharp.Memory;
  tests use Osysharp.Memory.Testing@0;   // only `osy test` loads this
}
```

Your test files import its names with `using` as usual.

### `minPlatform` — the oldest platform it runs on   {#min-platform}
`minPlatform "0.9.16";` names the oldest platform release the app may be built and run on. `osy init` writes it and
`osy compile`/`osy deploy` keep it at your CLI's release — see [minPlatform — the oldest platform an app runs on](https://osysharp.com/reference/project/min-platform/).

### A minimal manifest   {#minimal}
```osy title="the smallest useful manifest" test app=project-manifest-min
app Notes {
  model "model/**/*.osy";
  tests "tests/**/*.osy";
}

entity Note {
  [Required] string Title;
}
```

That is a complete application: it has a name, a model, and tests. Everything else is added when you need it.

### Two shapes of one app   {#named-manifest}
A project is its manifest's globs — so a **second manifest beside `app.osy`** is a second app built from the same
sources, selecting a subset of them. That is how one tree ships a full application and a cut-down one without a
second copy of the model to drift against.

```osy title="app-selfhost.osy — the same tree, a smaller model" syntax
app Notes {
  model "model/core/**/*.osy";   // app.osy globs model/**, this one only model/core/**
}
```

Build it by naming it, where a verb takes a project path:

```bash
osy validate app-selfhost.osy
```

Two rules keep this explicit rather than surprising:

- **A directory always resolves to `app.osy`**, never to anything beside it. `osy validate .` builds the full app
  whether or not a second manifest exists, so no project gains one by accident.
- **A named file is a manifest only if it declares an `app { }` block**, and that is parsed, not pattern-matched.
  An ordinary model file that merely mentions `app` in a comment or a string is not a manifest.

Both manifests may carry the same app name — they are two shapes of one app, not two apps — and each resolves its
globs against the directory it sits in, so they see the same tree. Omit `tests` from one and it carries no tests.

## See also       {#see-also}
- [project layout](https://osysharp.com/reference/project/layout/) — the folders the manifest's globs point at
- [use](https://osysharp.com/reference/types/use/) — `use` vs `using`, and version pins
- [Compiling your app](https://osysharp.com/reference/local/compiling-your-app/) — `osy compile`, which reads this manifest
- [Declaring the time zones and cultures an app uses — zones { } and cultures { }](https://osysharp.com/reference/i18n/zones-and-cultures/) — the `zones { }` and `cultures { }` blocks, which live in a model file
