> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orcra.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Structuring your manifest repository

> Your Git repository is the only control plane orun has. Learn how nodes/, deployments/, and services/ map to the three resource kinds orun manages.

In orun, the Git repository is the control plane. There is no dashboard, no API server, and no database storing desired state — everything lives in YAML files committed to Git. When you want to change what runs on a node, you change a file and push. The node picks it up on the next poll cycle.

## Directory layout

orun expects three top-level directories in your manifest repository. Each directory holds one kind of resource:

```text theme={null}
nodes/
  web-01.yaml
deployments/
  helloworld.yaml
services/
  helloworld.yaml
```

<Accordion title="nodes/">
  Node manifests describe a single host: its address, the Git repository and branch it should track, and runtime parameters such as poll interval and data directory. orun reads these files during `orun bootstrap` to provision new hosts. Committing node manifests to the repository means adding a new node is as simple as running `orun bootstrap nodes/<name>.yaml` — no manual configuration on the host.
</Accordion>

<Accordion title="deployments/">
  Deployment manifests describe a containerized workload: the image to run, port bindings, health check endpoints, volume mounts, and environment variables. Each file corresponds to one container managed by orun on every node that tracks this repository.
</Accordion>

<Accordion title="services/">
  Service manifests wire a Deployment to the built-in Caddy ingress: they specify which Deployment to expose, the public domain name, and whether to enable automatic SSL/TLS. The `ingress.domain.environment` field uses `$ENV` as a placeholder that orun replaces with the environment suffix at runtime.
</Accordion>

## Resource kinds

All resources share the same `apiVersion`. The `kind` field tells orun how to interpret the file.

```yaml theme={null}
apiVersion: run.orcra.dev/v0alpha
kind: Node | Deployment | Service
metadata:
  name: <resource-name>
spec:
  ...
```

### Node

```yaml theme={null}
apiVersion: run.orcra.dev/v0alpha
kind: Node
metadata:
  name: web-01
spec:
  host: 203.0.113.10
  user: root
  sshKeyPath: ~/.ssh/id_ed25519
  gitRepo: git@github.com:org/manifests.git
  gitBranch: main
  pollInterval: 5s
  dataDir: /opt/orun/
```

| Field          | Required | Default             | Description                                                     |
| -------------- | -------- | ------------------- | --------------------------------------------------------------- |
| `host`         | Yes      | —                   | SSH host or IP address of the target node                       |
| `user`         | No       | `root`              | SSH user for the bootstrap connection                           |
| `sshKeyPath`   | No       | `~/.ssh/id_ed25519` | Path to SSH private key on the machine running `orun bootstrap` |
| `gitRepo`      | Yes      | —                   | URL of the manifest Git repository                              |
| `gitBranch`    | No       | `main`              | Branch the node tracks after bootstrap                          |
| `pollInterval` | No       | `5s`                | How often the node polls for manifest changes                   |
| `dataDir`      | No       | `/opt/orun/`        | Local state directory on the node                               |

### Deployment

```yaml theme={null}
apiVersion: run.orcra.dev/v0alpha
kind: Deployment
metadata:
  name: hello-world
spec:
  image: traefik/whoami
  ports:
    - containerPort: 80
      port: 8080
  health:
    readiness:
      http: localhost:80/health
    liveness:
      http: localhost:80/health
  volumes:
    - hostPath: /var/storage/db
      containerPath: /db
  env:
    LOG_FORMAT: json
```

| Field                     | Required | Default      | Description                                                         |
| ------------------------- | -------- | ------------ | ------------------------------------------------------------------- |
| `image`                   | Yes\*    | —            | Container image to run. Mutually exclusive with `build`.            |
| `build.context`           | Yes\*    | —            | Build context path. Required when using `build` instead of `image`. |
| `build.dockerfile`        | No       | —            | Path to Dockerfile within the build context                         |
| `build.buildMode`         | No       | `build-once` | `build-once` or `watch`                                             |
| `ports[].containerPort`   | Yes      | —            | Port exposed by the container (1–65535)                             |
| `ports[].port`            | Yes      | —            | Host port to bind to (1–65535)                                      |
| `health.readiness.http`   | No       | —            | HTTP endpoint polled for readiness                                  |
| `health.liveness.http`    | No       | —            | HTTP endpoint polled for liveness                                   |
| `volumes[].hostPath`      | No       | —            | Path on the host to mount                                           |
| `volumes[].containerPath` | No       | —            | Path inside the container                                           |
| `env`                     | No       | —            | Environment variables passed to the container                       |

\*Exactly one of `image` or `build` is required.

### Service

```yaml theme={null}
apiVersion: run.orcra.dev/v0alpha
kind: Service
metadata:
  name: hello-world
spec:
  deployment: hello-world
  ingress:
    domain:
      default: hello-world.orcra.dev
      environment: hello-world.$ENV.orcra.dev
    ssl: true
```

| Field                        | Required | Default | Description                                                                                      |
| ---------------------------- | -------- | ------- | ------------------------------------------------------------------------------------------------ |
| `deployment`                 | Yes      | —       | Name of the Deployment to expose                                                                 |
| `ingress.domain.default`     | Yes      | —       | Domain used when no environment suffix applies                                                   |
| `ingress.domain.environment` | No       | —       | Domain template for environment-specific routing; `$ENV` is replaced with the environment suffix |
| `ingress.ssl`                | No       | `false` | Enable automatic SSL/TLS via Caddy                                                               |

## Git authentication

The node fetches from the `origin` remote of the manifest repository. Ensure the node has read access before running `orun bootstrap`.

<Tabs>
  <Tab title="SSH deploy key (recommended)">
    ```bash theme={null}
    # Generate a deploy key
    ssh-keygen -t ed25519 -C "orun@web-01" -f ~/.ssh/orun_deploy

    # Add the public key as a read-only deploy key in your Git host's UI,
    # then pass the private key path during bootstrap or in the Node manifest:
    sshKeyPath: ~/.ssh/orun_deploy
    ```

    Deploy keys grant read-only repository access to a single host, which limits blast radius if the key is ever compromised.
  </Tab>

  <Tab title="HTTPS token">
    ```bash theme={null}
    # Store the token in the Node spec or pass it during bootstrap.
    # orun supports HTTPS basic auth using a personal access token as the password.
    gitRepo: https://github.com/org/manifests.git
    ```

    <Warning>
      HTTPS tokens are typically scoped more broadly than deploy keys. Use a fine-grained token with read-only repository access.
    </Warning>
  </Tab>
</Tabs>

## Poll interval and change propagation

The node polls the `origin` remote every `pollInterval` seconds (default: `5s`). After you push a commit, the node picks it up within one poll cycle. Reduce `pollInterval` for faster convergence, or increase it to reduce Git API load on shared hosts.

```yaml theme={null}
spec:
  pollInterval: 10s   # node checks for changes every 10 seconds
```

<Tip>
  Commit your Node manifests to the repository. When you need to provision a new node, run `orun bootstrap nodes/<name>.yaml` against the committed file. You get a full audit trail of node configuration changes in Git history at no extra cost.
</Tip>
