# Self-hosted launch workload

Source: https://codeherder.com/docs/self-host-workload/

The launch workload for a first self-hosted customer, in one table with growth columns and a named source for each number, for load tests and sizing.

This page defines the launch workload for a self-hosted deployment. It covers people, agent sessions, devices, tasks, attachments, live sockets, webhooks and cost rows. Load tests use these numbers. Sizing decisions use them too.

You own the real workload. Replace these numbers with your own when you have them. See “Replace these numbers” below.

## Launch workload profile

Read one row at a time. The Launch column is the starting load. The 2x and 5x columns are the growth steps.

| Quantity | Launch | 2x | 5x | Unit | Source |
| --- | --- | --- | --- | --- | --- |
| Named people in the web app | 20 | 40 | 100 | people | Assumption: one engineering organisation of about 20 people. The hosted service has 5 people. |
| Concurrent people in the web app | 8 | 16 | 40 | people | Assumption: 40 percent of named people are signed in at one time. |
| Concurrent agent sessions | 30 | 60 | 150 | sessions | Measured on the CodeHerder hosted service, 2026-09-30: 33 live sessions across 9 devices, against 62 configured slots. |
| Devices | 9 | 18 | 45 | devices | Measured on the CodeHerder hosted service, 2026-09-30: 9 devices, 4 of them EC2 hosts. Add EC2 hosts in whole units. |
| Tasks created per hour, typical | 3 | 6 | 15 | tasks per hour | Measured on the CodeHerder hosted service, 2026-09-30: the median hour of the newest 200 tasks. |
| Tasks created per hour, peak | 175 | 350 | 875 | tasks per hour | Measured on the CodeHerder hosted service, 2026-09-30: the busiest hour of the newest 200 tasks. A planning stage created most of them. |
| Attachment uploads | 20 | 40 | 100 | uploads per hour | Assumption: screenshots and logs, at 2 or 3 per person per hour among concurrent people. Not measured. |
| Attachment downloads | 100 | 200 | 500 | downloads per hour | Assumption: 5 views per upload. Not measured. |
| Attachment size, typical | 1 | 1 | 1 | MiB | Assumption: a screenshot or a log excerpt. Not measured. |
| Attachment size, largest | 50 | 50 | 50 | MiB | The server file limit, `MaxSizeBytes` in the attachments package. Size does not grow with load. |
| Live attach sockets | 8 | 16 | 40 | sockets | Assumption: each concurrent person watches one live session. |
| Realtime subscriptions | 16 | 32 | 80 | subscriptions | Assumption: 2 browser tabs for each concurrent person. Each person is capped at 24. |
| Inbound webhook deliveries, typical | 2 | 4 | 10 | deliveries per minute | Assumption: git-host events from about 10 active repositories. Not measured. |
| Inbound webhook deliveries, peak | 30 | 60 | 150 | deliveries per minute | Assumption: a merge train or a bulk push sends a burst. Each body is 1 MiB or less. |
| Cost-ingest rows | 60 | 120 | 300 | rows per minute | Assumption: 2 model turns per session-minute across 30 sessions. One session sampled on 2026-09-30 wrote 5 turns in 13 seconds while it used tools. |

The measured rows come from one day of the hosted service, not a 7-day window. The tools an agent can use do not show webhook delivery history, so those rows are assumptions.

## Growth assumption

- **2x:** a second team joins. People, sessions and tasks double. You add devices.
- **5x:** a broad rollout. People, sessions and tasks grow five times.

Scale the rows in a straight line, with two exceptions:

- **Devices** grow in whole EC2 hosts. Each host runs about 8 sessions.
- **Webhook peaks** depend on repository activity more than on head count. Check them again before each step.

Before each step, check pool wait, device memory and app host memory. [Sizing a self-hosted deployment](https://codeherder.com/docs/self-host-sizing/) gives the starting sizes and the signals.

## Limits that bound this profile

The server caps these values. The profile stays below them.

| Limit | Value | Setting |
| --- | --- | --- |
| Attachment file size | 50 MiB | Fixed in the server |
| Inbound webhook body | 1 MiB | Fixed in the server |
| Realtime subscriptions for each person | 24 | `CH_REALTIME_MEMBER_SUBSCRIPTION_CAP` |
| Live attach sockets for each person | 8 | `CH_ATTACH_MEMBER_SOCKET_CAP` |
| Live attach sockets on one API process | 256 | `CH_ATTACH_SOCKET_CAP` |
| Records imported by each person | 5000 a minute, burst 20000 | `CH_IMPORT_RECORDS_PER_MIN`, `CH_IMPORT_RECORD_BURST` |
| Requests for each caller | 1200 a minute, burst 2000 | `CH_CALLER_RATE_PER_MIN`, `CH_CALLER_RATE_BURST` |

## Replace these numbers

Give your own values when you know them. The profile stays in this table format so that a load test can copy it.

- Count devices and live sessions with `ch device list`.
- Count tasks created in an hour with `ch task list --all`.
- Read webhook delivery times with `ch inbound-endpoint deliveries`. An owner or admin runs this command.
- Read cost rows for one session with `ch costs session-turns`.

## Related guides

- [Sizing a self-hosted deployment](https://codeherder.com/docs/self-host-sizing/) — size the app host, database and devices for this load
- [Self-hosted deployment](https://codeherder.com/docs/self-hosting/) — download, start, and upgrade the server
- [Managing your devices](https://codeherder.com/docs/devices/) — capacity limits and readiness checks
