# Publishing a project to Osyrin

> Puts a project from this computer on Osyrin, and later sends it its changes. You sign in with Osyrin's own sign-in, a publish is built here and served there, and the project remembers where it went in its own `osyrin.json` — so `osy link` (and Studio's Publish sheet) can say which app it is, which version people get, and whether the source has changed since.

<!-- id: local-publishing-to-osyrin · area: local · stability: preview · html: https://osysharp.com/reference/local/publishing-to-osyrin/ -->

## Summary        {#summary}

A project is **on Osyrin** once a publish of it has succeeded: `osy deploy --env <slug> --server <url>` builds it on
this computer, hands it to Osyrin, and Osyrin builds it again and serves it. That deploy writes the **link** into the
project's own `osyrin.json`: the server, the app, the environment, and the version and source it published.
`osy link` reads the link back and asks the server about it. Studio's **Publish** does the whole thing from a sheet,
through exactly these commands.

## Signature      {#signature}

```console
osy link [path] [--server <url>] [--offline] [--json]
osy apps [--server <url>] [--json]
osy migration explain <file> [--json]
osy deploy --env <slug> --server <url> [--app <slug>] [--migration <file>] [--json]
osyrin login --server <url> · osyrin whoami --server <url> [--json] · osyrin logout --server <url>
osyrin app create <name> --server <url> [--org <slug>] [--json]
```

## Description    {#description}

**Signing in is Osyrin's own.** `osyrin login --server https://osyrin.app` opens your browser on Osyrin's own sign-in
page ([Signing in to Osyrin](https://osysharp.com/reference/local/signing-in-to-osyrin/); `--no-browser` types it in the terminal instead) and keeps the sign-in in
`~/.osyrin/credentials.json`, under the server's apex address (`admin.osyrin.app` and `osyrin.app` are the same
sign-in). Every other verb uses that sign-in and none of them asks for a password:
`osyrin app create` included. `osyrin whoami --json` answers `{"signedIn": false, …}` when nobody is signed in, and a
tool asking with `--json` is never prompted.

**The link lives in the project.** After a publish succeeds, `osyrin.json` beside `app.osy` reads:

| field | what it is |
|---|---|
| `server` | the Osyrin it went to, by its apex address |
| `app` | the app on it, by its address name (on Osyrin Cloud, the project's name followed by your organization's: `greeter-acme`) |
| `environment` | the environment it went into, like `production` |
| `published` | `version`, `sourceHash` and `at`: what was published from here, and when |

It is an ordinary file of the project, so the link goes wherever the project goes and a teammate's copy sees the same
one. A deploy that is refused or fails writes nothing. The link is not in `osyrin.lock`, because the lock is part of
what a deploy builds.

**`osy link` says where the project stands.** It never changes anything and never prompts:

- **signed in** — who is signed in to the server, or that nobody is, with the command that signs in;
- **the app** — the linked one. `found` says the server has it; `address` is where people open it. An app the server
  holds under the project's **name** is never taken to be this project — a copy of a project has the same name — so it
  is given apart, as `sameName`, and becomes the project's app only when a publish from here goes to it (`--app`);
- **served** — the version people get in the linked environment;
- **changed** — whether the project's source now differs from what was last published from here. It compares the
  same source hash a deploy is identified by, so a change to any source file, test, the lock, an asset or a package is
  a change, and nothing else is;
- **declared secrets** — the names the source declares. Values are never read: give them on Osyrin, in the app's
  Secrets;
- **where a first publish can go** — your organizations, and their environments in rank order. For each organization,
  `cannotAdd` says when the project cannot be added there: its first version needs a newer platform (its
  `minPlatform`, as the next deploy would carry it) than the newest release the organization can run.

`--offline` answers from this computer alone: the link and whether the source changed. Without `--server` it asks
the server the link names.

**Adding a project** is two commands: `osyrin app create "<name>" --server <url>` makes the app (in your organization;
`--org` when you belong to several) and prints its address name, then `osy deploy --env <slug> --server <url> --app
<that name>` publishes the first version. **An update** is the deploy alone, because a successful deploy records the app
in the project's `osyrin.json`. A deploy to a remote Osyrin never picks an app by the project's name: a project with no
link to that server and no `--app` is refused, the refusal naming `--app <slug>` and, as "did you mean", the apps you
can see whose names are the project's or close to it. Under `--json`, `osy deploy` prints one
line of result on standard output — `succeeded`, `message`, `application`, `version`, `address` — and its progress on
standard error. A change to stored data that needs a migration is refused by Osyrin before the new version is served,
with the reason; people keep the version they have. See [Deploying your app to an environment](https://osysharp.com/reference/local/deploying-your-app/) for everything a deploy does.

**In Studio**, every project has **Publish**. The sheet runs `osy link` and says, before anything is pressed: who is
signed in; whether the project is on Osyrin and as which app; the version people get; what was asked of the builder
since the last publish; and **what will happen** — a new app in which organization and environment, or the next
version of the linked one, the data line above, and the secrets it still needs. **Add to Osyrin** runs `osyrin app
create` and then `osy deploy`; **Publish update** runs `osy deploy`. While it runs the sheet shows the deploy's newest
line; after, the version people get and the address, or the reason it was refused in Osyrin's words. Under the
project's name a line says "On Osyrin as … · published … · changed since" whenever the project has a link.

**Your organizations' apps.** `osy apps --server <url>` lists every app of the organizations you belong to on that
Osyrin — its organization, its address and the version people get — and each organization's **app slots**: how many
it uses and how many its plan gives (`2 of 3 app slots used`), counted exactly as Osyrin counts when an app's first
version starts running. An app that runs anywhere takes a slot; one that was only made takes none yet. It asks only:
it never fetches or syncs source. **An app's source lives on the computers it was written on**; Osyrin keeps the
built app, not the project. Studio's **On Osyrin** page draws this list and puts each app beside the project on this
computer whose `osyrin.json` links it — "On this computer as Greeter", with Open — or says **Not on this machine**.
Updating an app is opening its project and publishing.

**App slots before an Add.** `osy link` gives each organization's slots too, and Studio's Add says them before
anything is sent. With none free, Studio does not make the app — its first version would be refused when it
started — and says so: "Acme uses all 3 of its app slots, so another app would not start. A pro slot gives it one
more." A pro slot is one more app for an organization; it cannot be bought yet, so Studio shows it as coming soon.
In the same way, an organization that cannot yet run the platform the project needs is said before anything is sent,
in the deploy's own words, and Add makes nothing — rather than an app whose first version is refused.

**An app of the same name.** When the project is linked to nothing and Osyrin has an app of its name, the sheet says
so and offers both: **Publish to** that app, if this project is it, or **Add to Osyrin** as a new app. It never
offers "Publish update" over an app it only matched by name.

**A publish that needs a migration.** A change that removes something holding data — a field renamed, an entity
dropped — is refused before anything changes, and the refusal carries the migration Osyrin wrote from the change it
saw. Under `--json`, `osy deploy` prints it apart from the sentence, as `migration`. `osy migration explain <file>`
reads a migration with the same parser the deploy uses and says what each statement does: a rename keeps every value
under the new name; a drop retires the values for good (with the safer way: keep the field one more version, copy its
values, drop it in the next publish); a line the deploy only **guessed** — an inferred rename — is marked to check;
and a file that no longer parses is refused with its line. In Studio the refused sheet keeps the migration in the
project as `migrations/next.migration`, shows it in a field you can edit, explains it line by line (**Check what it
does**), and **Publish with this migration** runs `osy deploy --migration migrations/next.migration` with the file
exactly as you left it. It is the same `.migration` file as everywhere else (see [Renaming and removing things that hold data](https://osysharp.com/reference/project/renaming-and-removing/)
and [Running a function when a version deploys](https://osysharp.com/reference/project/running-a-function/) for `run F;`).

**Settings** has **Your Osyrin account**: who is signed in to the Osyrin Studio publishes to (`https://osyrin.app`
unless you name another), **Sign in to Osyrin**, which runs `osyrin login` in the background with no window of its own:
your browser opens on Osyrin's sign-in, you sign in there, and Studio never sees your password. If no browser opened,
Studio shows the address to open. And **Sign out**. Studio keeps only which Osyrin it
publishes to, in `.studio/publishing.json` in your projects folder; the sign-in is the CLI's.

## Examples       {#examples}

```console
osyrin login --server https://osyrin.app        # once: Osyrin's own sign-in
osy link --server https://osyrin.app            # not on Osyrin yet — your organizations and environments
osyrin app create "Greeter" --server https://osyrin.app      # prints its address name, e.g. greeter-acme
osy deploy --env production --server https://osyrin.app --app greeter-acme   # the first version; osyrin.json now links it
osy link                                        # on Osyrin as greeter-acme · serves 1.0.0 · nothing has changed since
osy deploy --env production --server https://osyrin.app       # an update, to the app osyrin.json links
osy apps --server https://osyrin.app            # Acme — 1 of 3 app slots used · greeter-acme 1.0.0
osy deploy --env production --server https://osyrin.app --json   # refused: a field was renamed — the result carries `migration`
osy migration explain migrations/next.migration # what each statement does, and what to check
osy deploy --env production --server https://osyrin.app --migration migrations/next.migration
```

## See also       {#see-also}

[Signing in to Osyrin](https://osysharp.com/reference/local/signing-in-to-osyrin/) — `osyrin login`: in the browser, or typed with `--no-browser`; how long it lasts.

[Deploying your app to an environment](https://osysharp.com/reference/local/deploying-your-app/) — what a deploy does, step by step, and how a failed one is put back.

[Opening Studio](https://osysharp.com/reference/local/opening-studio/) — Studio, where Publish lives.

[Giving a secret its value](https://osysharp.com/reference/local/giving-a-secret-its-value/) — secrets on this computer; on Osyrin they are given in the app's Secrets.
