systemg 0.58.2

An agent-friendly general process composer.
Documentation
---
title: Projects
---

# Projects

A **project** is a durable namespace that groups a set of services. Its identity
is its id — the key under the `projects:` map in your manifest. Because a single
resident supervisor can host many projects at once — and a single config file
can declare many projects — projects are how systemg keeps unrelated (or
related) workloads cleanly separated inside one running daemon.

<Info>
  One supervisor, many projects. You can run a database stack, a web API, and a
  batch of cron units as three independent projects under the **same** systemg
  process. They share the runtime but keep separate state, logs, and status —
  and you target each one by id with `-p/--project`.
</Info>

## Declaring a project

Projects live under the `projects:` map, keyed by id. One file can declare many:

```yaml
version: "2"
projects:
  arbitration:
    name: Arbitration
    services:
      worker:
        command: "python worker.py"
  gamecast:
    services:
      api:
        command: "python api.py"
```

Each key is the project id. Start the whole file and all its projects boot; the
first project becomes the primary and the rest register behind it. See
[Configuration](/how-it-works/configuration) for the full schema.

<Warning>
  Treat the project id as durable runtime identity. Changing it does not rename a
  project — it creates a **new** namespace, and the old one's running services
  become orphaned state (visible under `sysg status --all`). Rename freely with
  `name`; never rename by editing the id.
</Warning>

<Note>
  Top-level `services:` with no project form a **loose bundle** — they still run,
  and their state persists under `projects/__loose__/`. The older singular
  `project:` block still parses (with a deprecation warning) for existing
  single-project manifests; convert them with
  [`sysg migrate`](/how-it-works/commands/migrate). Prefer the `projects:` map
  once more than one project shares a supervisor.
</Note>

## `-p/--project` vs `-c/--config`

These two flags answer different questions, and knowing which to reach for is
the single most useful thing about projects.

| Flag | What it does |
|------|--------------|
| `-c` / `--config` | **Loads and registers** the config file on disk — **every project it declares**, plus any loose bundle. Use it the first time you start, or when you want to reload the manifest from a specific path. |
| `-p` / `--project` | **Targets a single project already registered** with the running supervisor, by its id. No file path required. |

The mental model: `-c` is *bring this file's projects into the supervisor from
disk*; `-p` is *act on one project the supervisor already knows about*.

<Info>
  `-c <file>` operates on the file as a whole. `sysg status -c stack.yaml` shows
  every project the file declares, not just the first — the file identifies
  "everything here," and `-p` narrows to one.
</Info>

```sh
# First start: register the project from its config
$ sysg start -c services/arbitration.yaml

# From now on, target it by id — no config path needed
$ sysg status -p arbitration
$ sysg logs -p arbitration -s worker
$ sysg restart -p arbitration
$ sysg stop -p arbitration
```

<Info>
  Every registered project stores the config path it was started from. That's
  why `-p` alone is enough for later commands — systemg looks up the project's
  recorded manifest for you. This is what makes multi-project workflows
  ergonomic: you register once with `-c`, then drive everything by `-p`.
</Info>

## How `-p` relates to `sysg restart`

`restart -p <id>` is where the stored config path pays off:

```sh
$ sysg restart -p arbitration
```

When `--config` is omitted, `restart --project` reuses the config path the
supervisor already recorded for that project and reloads it from disk. Manifest
changes are applied on reload:

- services added since the last load **start**
- services removed from the manifest **stop**
- changed commands **take effect**

You do not need to pass `-c` again once the project has a known config path.
Pass `-c` explicitly only when you want to reload from a *different* file.

<Warning>
  If the config you point at declares a different `project.id` than the one you
  target, systemg refuses the operation rather than silently switching
  namespaces. The flag, the config, and any service selector prefix must all
  agree on the project.
</Warning>

## Qualified service selectors

Anywhere you name a service, you can qualify it with its project using
`project_id/service_name`:

```sh
$ sysg restart -s arbitration/worker
$ sysg logs -s gamecast-dev/api
```

This is equivalent to passing `-p` plus the bare service name. If you supply
both a selector prefix and `-p`, they must match.

<Warning>
  A mismatch is an error, not a best-effort guess:

  ```
  project flag 'arbitration' does not match service selector project 'gamecast-dev'
  ```

  systemg would rather stop than act on the wrong project.
</Warning>

<Info>
  When a service name is unambiguous — it exists in exactly one registered
  project — you can drop the project qualifier entirely and systemg resolves it
  for you. If the same service name lives in **multiple** projects, systemg
  refuses and asks you to disambiguate with `-p`.
</Info>

## `-p` per command

`-p/--project` is accepted across the commands that act on running projects:

| Command | Effect of `-p <id>` |
|---------|---------------------|
| `start` | Start (or start a single service within) the named project. |
| `stop` | Stop the named project's services. Use `--supervisor` to shut everything down. |
| `restart` | Reload the project's stored manifest and restart its services. |
| `status` | Scope the status table to one project. |
| `logs` | Filter tailed logs to one project. |
| `inspect` | Inspect a service within a specific project. |