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

# Cloud sync, quotas, and retention

> What syncing a report does, what it costs against your plan, when it expires, and what is never gated.

Syncing is opt-in, per scan, and asked once. Nothing syncs automatically, and a scan is
never blocked by the cloud.

<Warning>
  "The cloud" here means a Myrqen deployment. **There is no hosted Myrqen service today**, so
  everything on this page requires [a deployment you run yourself](/guides/self-host) plus a
  [linked device](/getting-started/link-a-device). On an unlinked machine the CLI says
  `This device is not linked, so this scan stays local.` and carries on.
</Warning>

## What is always free

A finding discovered on your machine is never paid content. These capabilities are
unconditional, on every plan:

`local_scan` · `local_report_html` · `local_report_json` · `local_report_markdown` ·
`local_report_sarif` · `copy_fix_prompt` · `apply_fix_locally` · `device_management`

## What syncing adds

<CardGroup cols={2}>
  <Card title="A live report URL" icon="bolt">
    Printed immediately, before the scan finishes. A phase timeline, elapsed time, and
    aggregate counts — with no fake progress percentage.
  </Card>

  <Card title="Sharing" icon="share-nodes">
    One URL that renders differently per recipient, filtered on the server.
  </Card>
</CardGroup>

## The sync question

In an interactive terminal, once per scan:

```
Sync this report to Myrqen for live progress and sharing? [Y/n]
```

An agent has no terminal, so the CLI does not guess — `cloud.state` comes back as
`decision_required` and the agent asks the user, then records the answer:

```bash theme={null}
myrqen --json session sync-decision yes    # or: no
```

The CLI does not ask a question that cannot succeed. If the device is unlinked, the
repository is unbound, or quota is exhausted, it says so and continues locally.

## What crosses the boundary

Only what the sync contract names.

**Sent:** report prose, explicitly selected evidence, redacted secret *references* (a
label, a kind, a local HMAC fingerprint), and safe high-level scan metadata — effort,
duration, agent and model, phase timings, aggregate counts.

**Never sent:** secret values, model provider keys, the repository, raw network capture.
`policy.uploadFullRepository` is `false` in every session context, and the progress
endpoint's schema is closed so source, prose, or evidence cannot travel through it even by
accident.

## Plan limits

From `packages/entitlements/src/index.ts`:

|                               | `free` | `pro` | `team` | `enterprise` |
| ----------------------------- | ------ | ----- | ------ | ------------ |
| Cloud reports per day         | 5      | 25    | 100    | 1000         |
| Cloud reports per week        | 15     | 100   | 500    | 5000         |
| Retention (days)              | 21     | 180   | 365    | 1095         |
| Active share links per report | 5      | 25    | 100    | 1000         |
| Team workspaces               | —      | —     | yes    | yes          |
| Workspace audit               | —      | —     | yes    | yes          |
| Configurable retention        | —      | yes   | yes    | yes          |
| SSO / SCIM                    | —      | —     | —      | yes          |

## Quota windows

Quota boundaries are **UTC-anchored**, never derived from a locale or from daylight saving
time.

* The quota **day** runs 06:00:00 UTC to 06:00:00 UTC.
* The quota **week** runs Monday 06:00:00 UTC to Monday 06:00:00 UTC.

```bash theme={null}
myrqen status     # usage and the exact reset instants
```

Read it over the API with [`GET /api/v1/sync-quota`](/api-reference/introduction):

```json theme={null}
{
  "eligible": true,
  "daily":  { "used": 2, "limit": 5,  "resetsAt": "2026-08-21T06:00:00.000Z" },
  "weekly": { "used": 7, "limit": 15, "resetsAt": "2026-08-24T06:00:00.000Z" },
  "retentionDays": 21,
  "plan": "free"
}
```

When blocked, `blockedBy` is `daily`, `weekly`, or `both`, and the CLI says which:

> Cloud report limit reached (daily). This scan will stay local. Limit resets Friday 06:00
> UTC. You can run "myrqen sync rpt\_…" after that.

## Sync an earlier local report

```bash theme={null}
myrqen reports                       # local reports and their cloud state
myrqen sync <localReportId>          # recheck login, device, and quota, then sync
```

`sync` refuses while quota is blocked. Nothing ever syncs on its own.

## How a sync unit is spent

The unit is **reserved** when the report shell is created and **spent** at finalize.

That ordering is deliberate: an object-storage failure during the upload leg no longer
burns one of the day's cloud reports with no way to get it back. A retried request reuses
the same reservation — keyed on the local report id — and never charges twice. If the
shell cannot be created at all, the reservation is released.

## Retention

|            |           |
| ---------- | --------- |
| Free       | 21 days   |
| Pro        | 180 days  |
| Team       | 365 days  |
| Enterprise | 1095 days |

Expiry is measured from the sync instant. When a report expires, `apps/worker` deletes the
body and its stored object, share links stop working, the report page explains the expiry,
and the API answers `REPORT_EXPIRED` (HTTP 410).

Your local report files are untouched.

## Billing

Payments go through Polar. All four Polar variables are required together or the
application refuses to start — a half-configured payment path takes money and grants
nothing. Left unset, the deployment sells nothing: the pricing page still renders and says
checkout is unavailable.

The plan is never taken from the request. It is resolved from the product id through the
deployment's own configuration, so a forged product cannot map to an entitlement that was
not sold. See [Self-host](/guides/self-host#payments-optional).
