# How packages, connections, capabilities and services fit together

Seven terms name the ways an app reaches past its own code: package,
provider, connection, driver, capability, built-in service and service
run by Jadpo. This topic says what each one is and where it runs. The
topics it links hold the rules.

Most apps use only two of them. A *connection* in `app.jadpo` opens a
database or a provider's API, and your actions call through it. You
don't need Docker or Podman for any of this: only a service run by Jadpo
uses a container.

## What each one is

| Term | What it is | Declared in | Runs |
|---|---|---|---|
| **Package** | Jadpo source shared between apps, laid out as `shared/` is. A *library package* holds types, failures and pure functions (`Postcodes.uk.parse`); a *provider package* describes one outside API: its operations, types, failures, webhook events and how it is reached ([Kinds of package](kinds-of-package.md), [The package format](the-package-format.md)) | `packages/<name>/<version>/` when installed; the app's own in `shared/providers/` | Compiled into the app and run in its process. A package is never a process, a container or native code of its own |
| **Provider** | The outside API a provider package describes: Stripe, a courier, another Jadpo app, Gotenberg. The package's `provider.jadpo` says how it is reached | Nowhere in the app: it is the other end of the call | Wherever its owner runs it: on the internet (`hosts:`), at an address a setting gives (`host:` on the connection), or in a container Jadpo starts (`runs:`) |
| **Connection** | One named entry in `connections:` in `app.jadpo`: a built-in driver (`driver: Driver.x`) or a provider package (`package: X.vN`), with its settings, its credential and the domains whose actions may call it. One connection is one resource: a database, a bucket, one account at a provider ([Connecting in `app.jadpo`](connecting-in-app-jadpo.md)) | `app.jadpo`, its values read from `config.jadpo` settings | Opened by the runtime, inside the app |
| **Driver** | Native code in Jadpo's runtime that speaks one protocol: PostgreSQL, SMTP, the disk, Cloudflare Queues, OpenAI-compatible model servers; Redis, S3 and OpenID Connect to come. Drivers arrive only with a Jadpo release, never in a package ([No presets, no dependencies](the-package-format.md#no-presets-no-dependencies)) | `driver:` on a connection | Inside the app, talking to a server the operator runs |
| **Capability** | A job Jadpo itself does, with one API in app code whatever fills it: `database`, `cache`, `files`, `email`, `search`, `documents`, `ai` and the rest. One connection fills it: a driver, or a provider package whose `provides/<capability>.jadpo` maps the job onto its operations ([Capabilities](capabilities.md)) | Chosen in `app.jadpo`: `email: { connection: mail }`, `store: sheets` on a `File` field | Wherever the connection that fills it runs |
| **Built-in service** | A backend feature Jadpo provides, so the app installs nothing: feature flags, rate limits, files, email, audit, telemetry, search, documents, bot protection ([Built-in services](built-in-services.md)). Email, files, search and documents do their outside work through a capability; flags, rate limits and audit keep their state in the app's own stores | Where [Built-in services](built-in-services.md) says: `flags.jadpo`, `rate_limit:`, `type X = EmailMessage`, `File` fields | Inside the app's runtime. It is a feature, not a process or a container |
| **Service run by Jadpo** | A provider whose API is a stateless container image, declared by `runs:` in its package's `provider.jadpo` (Gotenberg turning HTML into PDFs, ClamAV scanning uploads). Jadpo starts and supervises the container through Docker or Podman and hands its connection the address ([Services](what-package-code-may-do.md#services)) | `runs:` in the package, named by a connection | A container beside the app on the same machine |

Two words mean two things each:

- **"Service".** A built-in service is part of Jadpo's runtime, inside
  the app's process; a service run by Jadpo is a container beside it. No
  built-in service starts a container; one can use a service run by Jadpo
  through its capability, as documents can use Gotenberg.
- **`runs:`.** In a package's `provider.jadpo` it declares a container;
  on a deployable in `app.jadpo` it lists the background work that
  deployable runs, `runs: [Trigger.schedules]`
  ([Declared deployables](declared-deployables.md)).

## How they relate

```text
the app's process: jadpo dev's interpreter, or a native or Workers deployable
│
├── domain code ── calls ──► library package             pure functions, in process
│
├── domain code ── calls ──► connection: provider package ── HTTPS ──► provider's API
│                                                    on the internet (hosts:), at host:,
│                                                    or in a container Jadpo runs (runs:)
│
└── built-in services: flags, rate limits, email, files, search, documents, ...
       │ outside work goes through a capability
       └──► capability: email, files, database, documents, ai, ...
              filled by one connection, either
              ├── a built-in driver ──────────── its protocol ──► a server the operator runs:
              │                                                  PostgreSQL, SMTP, S3
              └── a provider package's provides/ ── HTTPS ──────► provider's API:
                                                                 Resend, Postmark, Gotenberg
```

- **Code calls a provider's operations only through a connection**, from
  an action in a domain the connection lists: `couriers.bookings.create(...)`
  ([Calling](calling.md)).
- **Code never names what fills a capability.** It writes an
  `EmailMessage` type or a `File` field, and `app.jadpo` picks the
  connection, so changing provider changes `app.jadpo` and its settings,
  never domain code.
- **One provider package can be both.** Postmark fills `email` through
  `provides/email.jadpo`, and the domains its connection lists call its
  own operations (hosted templates, suppression lists) as any provider's.
- **Packages fill capabilities and never invent them**, never bring a
  driver and never depend on another package.
- **Anything that keeps data is the operator's.** PostgreSQL, Redis, an
  S3 bucket and an SMTP server are reached through a driver at the
  address a setting gives; Jadpo never runs them. A service run by Jadpo
  holds no data, and each app instance runs its own copy.

## Where each runs

| | `jadpo dev` | `jadpo test` | Native deployable | Workers deployable |
|---|---|---|---|---|
| Library package | In process | In process | Compiled in | Compiled in |
| Provider package's calls | Faked by default, from its recordings or generated answers; operations named in `development: { sandbox: }` go to the sandbox, never live ([Provider calls in development](provider-calls-in-development.md)) | Always faked; a test scripts answers with `fakes:` ([Tests and fakes](tests-and-fakes.md)) | HTTPS to the live or sandbox host the connection's `environment:` picks, or to its `host:` | The same, through the Worker's `fetch` |
| Database, `Driver.postgres` | The address its setting gives, else a disposable PostgreSQL started from the machine's PostgreSQL tools | A copy per test on a disposable PostgreSQL, or on `JADPO_TEST_DATABASE_URL`'s server | The operator's PostgreSQL | The operator's PostgreSQL, through Hyperdrive |
| Email, by SMTP or a mail package | Caught in the dev inbox | Caught in `email.sent` | The SMTP server, or the mail package's API | The same; SMTP on port 587 only |
| Files | The disk driver, in `.jadpo/files/` | An in-memory store | The disk (one server) or S3 | S3, R2 included |
| Service run by Jadpo, `runs:` | Started as a container by `jadpo dev` | Never started: the package's fake answers | A container beside the app: `jadpo build` writes the configuration that runs it (Compose first), then the deployable supervises it itself | None: Workers runs no containers, so the connection gives `host:` where the service is hosted elsewhere |

`jadpo check` refuses a deployable whose target can't run a connection
it reaches, naming what to use instead: on Workers the disk, a service
run by Jadpo without `host:`, and SMTP on port 25
([Capabilities](capabilities.md), "Targets").

## How Docker fits

- **An app needs no Docker or Podman** to be checked, tested, run in
  `jadpo dev` or built. Nothing above but a service run by Jadpo uses a
  container: the disposable PostgreSQL comes from the machine's own
  PostgreSQL tools, a native deployable is one binary
  ([A native deployable](a-native-deployable.md)) and a
  Workers deployable is a Worker. Neither is an image.
- **Docker or Podman comes in only for a service run by Jadpo.** Jadpo
  talks to whichever engine the machine has, through the
  Docker-compatible API both serve. It creates each container itself. A
  container has no outbound network until its connection grants it, is
  never privileged and can't reach the host's disk. A new or changed image
  runs only once a person accepts it in the approval report.
  `jadpo services` lists, starts and stops each one and shows its logs
  ([Tooling](tooling.md)). You never write a Dockerfile or a Compose
  file, and an app with no such connection never needs an engine
  ([Services](what-package-code-may-do.md#services)).
- **The operator's infrastructure is their own.** They may run
  PostgreSQL or an SMTP server in Docker, or anywhere else; the app sees
  only the address its setting gives.

## In an app

One app with each kind of connection: a database on the PostgreSQL
driver, mail on the SMTP driver filling the `email` capability, and the
app's own provider package for a courier, which the `shipping` domain
calls:

```jadpo
application {
    connections: {
        main: {
            driver: Driver.postgres
            url: config.database_url
        }
        mail: {
            driver: Driver.smtp
            host: config.smtp_host
            credential: {
                username: config.smtp_username
                password: config.smtp_password
            }
        }
        couriers: {
            package: AcmeCouriers.v1
            domains: [shipping]
            credential: config.couriers_api_key
            environment: config.couriers_environment
        }
    }
    email: {
        connection: mail
        from: config.mail_sender
    }
}
```

```jadpo
use app { couriers }
use shipping/failures { SlotGone }
use shared/providers/acme_couriers

/// Books a collection with the courier, through its connection.
action book(postcode: AcmeCouriers.Postcode) fails SlotGone -> AcmeCouriers.Booking {
    return attempt couriers.bookings.create(
        AcmeCouriers.CreateBooking {
            postcode: postcode
        }
    ) {
        slot_taken: SlotGone
    }
}
```

A service run by Jadpo: Gotenberg's package declares its container, and a
connection to it fills the `documents` capability. In `jadpo dev` and a
native deployable, Jadpo starts the container. On Workers the connection
would give `host:` instead:

```jadpo
// packages/gotenberg/v8/provider.jadpo
/// Gotenberg's HTTP API, run by Jadpo as a container beside the app.
provider {
    protocol: Protocol.multipart_http
    runs: {
        image: "gotenberg/gotenberg:8@sha256:…"
        port: 3000
        asks: ["fonts.googleapis.com"]
    }
}

// app.jadpo
application {
    connections: {
        pdfs: {
            package: Gotenberg.v8
            domains: [billing]
            outbound: ["fonts.googleapis.com"]
        }
    }
    documents: {
        connection: pdfs
    }
}
```

## What is built of these

Built: library and provider packages, installed from a folder or git
and locked; connections and the network report; provider calls with
decoding, retries and idempotency keys; fakes in development and tests,
recordings and sandbox calls; webhooks, queues, polls and package
actions; the drivers for PostgreSQL, SMTP, the disk (in `jadpo dev` and
tests), Cloudflare Queues and OpenAI-compatible servers; the `database`,
`email` (SMTP, Resend and other mail packages), `receiving`,
`schedules` and `ai` capabilities; and the built-in services email,
rate limits and the first part of files.

Not built yet: **services run by Jadpo** (`runs:`, `jadpo services`,
and with them every use of Docker or Podman); the Redis and S3 drivers
and a deployable's disk; OpenID Connect sign-in providers and OAuth
grants; the `cache`, `publishing`, `search`, `documents`, `bot_check`
and `scanning` capabilities; the built-in services flags, audit,
telemetry's section, search, documents and bot protection; the hosted
registry; importers other than `openapi`; and choosing a provider when
deploying. Each page's "What is built" table is the record.
