# Composing kits — what they give together, and what is left for you

> Before any code, shows what a set of kits gives together — the bridges that arrive by themselves, every event with its handlers in the order they run, slots and their contributions, records, actions, nav — and what is LEFT for your app: the policies to define, the settings to fill and the bases to derive, each with the kit's test app line that does it.

<!-- id: local-composing-kits · area: local · stability: stable · html: https://osysharp.com/reference/local/composing-kits/ -->

## Summary        {#summary}

`osy compose` answers the question to ask after choosing kits and before writing code: **what do these give together,
and what is left for me?** Named kits are composed as a dry run — with every kit they use, and every bridge that
completes a pair among them. Run inside an app (or with `--app <dir>`), it composes what the app uses together with the
app's own code, so what is left is what the app has not done yet.

```console
$ osy compose Osysharp.SatisfactionSurveys Osysharp.Notifications
Composing Osysharp.SatisfactionSurveys, Osysharp.Notifications — 8 kit(s) with what they use

kits      Osysharp.Identity · Osysharp.Ui · Osysharp.Workflow · Osysharp.TimeZone · Osysharp.EmailTemplates · Osysharp.Mail · Osysharp.SatisfactionSurveys (vertical) · Osysharp.Notifications

events — handlers in the order they run, after the commit
  heard by no handler of its own (1) — `[On] void H(TheEvent e) { … }` hears one: FeedbackAnswered (Osysharp.SatisfactionSurveys)

left for you
  define  policy ManagesFeedback (Osysharp.SatisfactionSurveys) — Who decides whether, when and for how long people are asked — the settings page.
          its test app: policy ManagesFeedback => IsOwner;
  define  policy ReadsFeedback (Osysharp.SatisfactionSurveys) — Who reads the answers and the results — the people who did the work, and whoever looks after how it goes.
          its test app: policy ReadsFeedback => IsMechanic;
  define  policy ReceivesNotifications (Osysharp.Notifications) — Who has a bell and notification preferences — the people the app tells things.
          its test app: policy ReceivesNotifications => IsWriter;
  may define  policy ManagesClock (Osysharp.TimeZone; has a default) — Who may move the app's clock — the app's admins, unless the app says otherwise: …
          its test app: policy ManagesClock => IsOwner;
```

## Signature      {#signature}

```console
osy compose <kits…>          # a dry run over these kits, what they use, and the bridges among them
osy compose [--app <dir>]    # what this app uses, with its own code (the default inside an app)
  --diff +<kit>              # what one more kit adds
  --effects                  # what each handler can create, change, delete, raise or send (always on in an app)
  --project <dir>            # where to look for kits — the workspace above it, its lock
  --offline                  # only kits on this machine: no newest release from GitHub, no bridge search there
  --json                     # { composition: { packages, events, slots, extensions, records, actions, settings, nav, left } }
```

## Description    {#description}

### What it prints    {#what}

- **kits** — every kit in the composition, a product kit marked `(vertical)`, and each **included** bridge with why it
  arrived (`completes Osysharp.WorkQueues + Osysharp.Notifications`) and how to keep it out (`without …;`).
- **records** — each record type with a title, the page that opens it and the actions offered on it.
- **events** — each event with who raises it and its handlers **in the order they run**: `[Order]` (default 100), then
  the package — a kit before the kits built on it, your app last — then the name. The handlers that hear every event
  (automations, webhooks, a timeline) are said once. Events nothing hears specifically are listed on one line.
- **slots** — each slot with its contributions in drawing order; a slot nothing fills is shown, not an error.
- **extension members** — the members a bridge (or your app) adds to another kit's record.
- **nav** and **settings pages** — the entries each kit adds.
- **left for you** — what the composition still needs from your app: each **policy** a kit asks for and the app has
  not defined (with the kit's test app's line that defines it), each **setting** whose fields have no default, each
  **abstract base** with no type of your own.

### Two kinds of account    {#identity}

An app has ONE `[Principal]` (who signs in is one table), one `[Role]` enum, and one sign-in. A set of kits that brings
two of any of them is said FIRST, before everything else, because it is not one app: the compile refuses the first two,
and of two kits that each wire a sign-in only one is ever reached. The line names both declarers — and a kit you never
named by the kit that brought it, so the `use` to drop is the one in your app. In an app that declares its own roles and
uses the shop, whose roles are the shop's:

```console
$ osy compose
⚠ two role vocabularies: `AppRole` (this app) and `ShopRole` (Osysharp.Shop). An app has only ONE `[Role]` enum — the roles a sign-in carries, counted across the app and every kit it uses, so this set does not compile as one app. Keep one kit's accounts: drop `Osysharp.Shop` (or your own) from the set, or use a kit that builds on the other's.
```

Kits that BUILD ON one another share one identity and are not a clash: the shop's `ShopAccount` is an Osysharp.UserAccounts
`User`, itself an Osysharp.Identity `Principal`, so the shop composes with every kit on that identity — feedback,
invitations, the people kit.

`--diff +<kit>` says it when the kit it adds is what brings the second; `--json` carries the lines as `clashes`.

### What a handler can change    {#effects}

`--effects` resolves the composition and prints, beside each handler, what it — and everything it calls — can create,
change, delete, raise or send out. In an app it is always on. It is the review to make before a kit's handler runs on
your data:

```console
events — handlers in the order they run, after the commit
  every event is heard by RunRules (Osysharp.Automations, only what its [Interest] names), SendOut (Osysharp.Webhooks, only what its [Interest] names), InboxOnTheTimeline (this app, only what its [Interest] names)
    RunRules · creates AutomationFire; changes AutomationFire; and calls whose effects are not known here
    SendOut · creates WebhookDelivery; and calls whose effects are not known here
    InboxOnTheTimeline · creates ConversationEvent; changes Conversation
  FeedbackAnswered (Osysharp.SatisfactionSurveys raised by ApplyFeedbackReply)
    → TicketAnswered (this app) · creates ConversationEvent, Notification; changes Conversation, Ticket; Policy.CheckFor
```

### One more kit    {#diff}

`--diff +<kit>` composes once without the kit and once with it, and prints only what it adds: the kits (with any bridge
it completes), the handlers it brings to events already there, contributions, nav, extension members, and the policies
and settings it leaves for you.

### The same data in `osy model`    {#model}

`osy model --json` carries the app's composition as `composition` — the same shape `osy compose --app . --json` prints —
for a tool ([Understanding your app](https://osysharp.com/reference/local/understanding-your-app/)).

## See also       {#see-also}
- [Connecting a kit — each seam with the code that connects it](https://osysharp.com/reference/local/connecting-a-kit/) — each seam of one kit, with the code that connects it
- [Finding a kit, and learning one from its tests](https://osysharp.com/reference/local/finding-a-kit/) — `osy kits find`: kits by what they do
- [Bridges — a package that arrives when an app uses the two it completes](https://osysharp.com/reference/project/bridges/) — `completes`, and how a bridge arrives by itself
- [[On] — hear an event, after the commit that raised it](https://osysharp.com/reference/function/on/) — hearing an event, and the order handlers run in
- [Slot (child content)](https://osysharp.com/reference/ui/slots/) — slots and contributions
