From 92509dd190b41c706a98d70f20c31e9677f2b6a6 Mon Sep 17 00:00:00 2001 From: August Cayzer Date: Wed, 21 Oct 2026 05:33:46 +0100 Subject: [PATCH 1/8] docs(guides): align console operations with live contract --- content/docs/(overview)/access.mdx | 14 ++++++++++---- content/docs/(reference)/cli.mdx | 2 ++ content/docs/guides/audit-log.mdx | 2 +- content/docs/guides/back-up-and-restore.mdx | 2 +- content/docs/guides/housekeeping.mdx | 15 +++++++++------ content/docs/guides/run-a-connector.mdx | 6 ++++++ content/docs/guides/settings.mdx | 21 +++++++++++++++------ content/docs/guides/upgrade.mdx | 10 +++++----- 8 files changed, 49 insertions(+), 23 deletions(-) diff --git a/content/docs/(overview)/access.mdx b/content/docs/(overview)/access.mdx index 3832800e..cbd3e19e 100644 --- a/content/docs/(overview)/access.mdx +++ b/content/docs/(overview)/access.mdx @@ -11,11 +11,13 @@ Three kinds of caller act on an instance: | Caller | How it acts | What it reaches | | --- | --- | --- | -| The owner | Signs in to the instance in a browser | Managing the instance, reading item counts, and exporting data | +| The owner | Signs in to the instance in a browser | Managing the instance, listing item summaries, managing the trash, reading item counts and exporting data. | | A key | Sent with each request, as `Authorization: Bearer marfa_k1_…` | What it was made with | | An app | Signs in through OAuth, and sends its access token, `marfa_at_…` | What the owner approved | -Every other item operation needs a key or an app's token. A request that sends one is judged by that credential alone, even from a signed-in browser, and no key or app gets the owner's authority. [Sign in as the owner](/guides/sign-in-as-the-owner) shows how. +**The owner can list item summaries, manage the trash, read item counts and export data through a browser session**, without making a key. A summary gives an item's ID, type, version, name, source and creation time, but no properties, metadata, history or edges. The Items page searches names, not item content. The Trash page also shows when and by whom an item was trashed, and can move, restore or purge items. Those writes require a sign-in from the last five minutes. Both listings apply the instance's source filtering; an owner browser session still cannot open an item's content. + +Other item content operations need a key or an app token. If a request sends a credential alongside the owner's browser session, that credential alone decides its access. No key or app ever gets the owner's authority, whatever it holds. [Sign in as the owner](/guides/sign-in-as-the-owner) shows how the owner signs in, with a password or a passkey. Some owner actions need a **recent sign-in**, one from the last five minutes, such as revoking a key or an app, adding or changing a passkey, or approving an app's request to write or to hold a permission. @@ -71,6 +73,10 @@ The **Approve access** page, or the device approval page for an app with no brow - **Your profile:** only when the app asks for it. - **More control over Marfa:** each permission starts off. `instance.maintain`, `schema.write` and `items.purge` are marked because they can't be undone. -Approving with everything new off **is declining**: the app gets `access_denied` and keeps what it held. Approving a write or a permission the app doesn't hold needs a [recent sign-in](#who-can-act), so the page asks the owner to [confirm it's them](/guides/sign-in-as-the-owner#confirm-its-you), and a program without one gets `403 forbidden` and no code. The approval stands until the owner revokes it, or the app goes unused for a year, a limit [Settings](/guides/settings) can change with `MARFA_GRANT_INACTIVITY_DAYS`. +Approving with everything new off **is declining**: the app gets `access_denied` and keeps what it held. Approving a write or a permission the app doesn't hold needs a [recent sign-in](#who-can-act), so the page asks the owner to [confirm it's them](/guides/sign-in-as-the-owner#confirm-its-you), and a program without one gets `403 forbidden` and no code. + +The owner can later **narrow the approved access**. Tokens and refresh chains that exceed the remaining grant stop working immediately, while covered tokens keep working. Giving the app wider access again requires fresh approval. + +The approval stands until the owner revokes it, or until the app goes unused for the configured inactivity period. [Authenticate](/guides/authenticate) shows an app's side of it. -The rules behind this page are in the [keys and sign-in](https://github.com/withmarfa/marfa/blob/main/conformance/spec/keys-and-oauth.md), [authentication](https://github.com/withmarfa/marfa/blob/main/conformance/spec/authentication.md), [owner counts and exports](https://github.com/withmarfa/marfa/blob/main/conformance/spec/search-and-filters.md#search-and-filtersowner-count-export), and [instance claim](https://github.com/withmarfa/marfa/blob/main/conformance/spec/instance-claim.md) chapters of the contract. +The rules behind this page are in the [keys and sign-in](https://github.com/withmarfa/marfa/blob/main/conformance/spec/keys-and-oauth.md), [authentication](https://github.com/withmarfa/marfa/blob/main/conformance/spec/authentication.md), [owner summaries](https://github.com/withmarfa/marfa/blob/main/conformance/spec/search-and-filters.md#owner-item-summaries), [owner trash management](https://github.com/withmarfa/marfa/blob/main/conformance/spec/items.md#owner-trash-management), [owner counts and exports](https://github.com/withmarfa/marfa/blob/main/conformance/spec/search-and-filters.md#search-and-filtersowner-count-export), and [instance claim](https://github.com/withmarfa/marfa/blob/main/conformance/spec/instance-claim.md) chapters of the contract. diff --git a/content/docs/(reference)/cli.mdx b/content/docs/(reference)/cli.mdx index 1a57b9fb..a191e43a 100644 --- a/content/docs/(reference)/cli.mdx +++ b/content/docs/(reference)/cli.mdx @@ -147,6 +147,8 @@ That's how the owner makes the first key in the [Quickstart](/quickstart). These | `marfa owner recover` | Set a new owner password. | [Sign in as the owner](/guides/sign-in-as-the-owner#recover-the-owners-password) | | `marfa owner update` | Change the owner's email and name. | [Sign in as the owner](/guides/sign-in-as-the-owner#change-the-owners-profile) | | `marfa owner passkeys` | Add, list, rename and remove passkeys. | [Sign in as the owner](/guides/sign-in-as-the-owner#manage-passkeys-and-sign-ins) | +| `marfa items summaries` | List item summaries without opening item content. | [Access](/access#who-can-act) | +| `marfa items trash` | List, move, restore and purge items in the trash. | [Housekeeping](/guides/housekeeping#empty-the-bin) | | `marfa sign-ins` | List, rename and end the sign-ins that can reach the server. | [Sign in as the owner](/guides/sign-in-as-the-owner#manage-passkeys-and-sign-ins) | **The socket carries no key.** `--socket` can't be combined with `--url`, `--key`, `MARFA_API_URL` or `MARFA_API_KEY`. An operation that needs a key, such as `marfa events` or `marfa export`, ends with exit code 5, so run it with a key instead. `marfa login`, `logout`, `device`, `folders`, `docs` and `types scaffold` refuse `--socket`. diff --git a/content/docs/guides/audit-log.mdx b/content/docs/guides/audit-log.mdx index 0fbeae6c..424f95f8 100644 --- a/content/docs/guides/audit-log.mdx +++ b/content/docs/guides/audit-log.mdx @@ -116,7 +116,7 @@ marfa audit --resource-type item --resource-id 01a16970-ceb9-7a31-a880-857c997d1 The HTTP request is `GET /audit?resource_type=item&resource_id=`. -`marfa audit` takes the first five of these and not `kind` or `q`. +`marfa audit` takes all seven filters. Use `--kind` for `kind` and `--query` for `q`. [The audit kinds](https://github.com/withmarfa/marfa/blob/main/conformance/spec/events.md#eventsaudit-kind) and [the search](https://github.com/withmarfa/marfa/blob/main/conformance/spec/events.md#eventsaudit-search) hold the rules. **There is no filter for `key_id`**, so to see what one key did, read the entries and compare their `key_id`. diff --git a/content/docs/guides/back-up-and-restore.mdx b/content/docs/guides/back-up-and-restore.mdx index 9a7cba0a..937f68df 100644 --- a/content/docs/guides/back-up-and-restore.mdx +++ b/content/docs/guides/back-up-and-restore.mdx @@ -3,7 +3,7 @@ title: Back up and restore description: Copy an instance's data directory and secrets so you can bring it back after a failed disk or a lost machine. --- -Keep a copy of your instance somewhere the instance isn't. A copy of the data directory brings the same instance back with everything in it: items, keys, configuration and sign-ins. To carry your data into another instance instead, such as a new build, [export an archive](/guides/export-and-restore). +Keep a copy of your instance somewhere the instance isn't. A copy of the data directory brings the same instance back with everything in it: items, keys, configuration and sign-ins. To carry your data into another instance instead, [export an archive](/guides/export-and-restore). A different build may refuse the archive; [Upgrade](/guides/upgrade) explains how to test it before switching. ## What to copy diff --git a/content/docs/guides/housekeeping.mdx b/content/docs/guides/housekeeping.mdx index 0c8b2b4f..e767e603 100644 --- a/content/docs/guides/housekeeping.mdx +++ b/content/docs/guides/housekeeping.mdx @@ -63,12 +63,9 @@ Each run reports `moved` and `held` in `last_result`. `moved` includes items a c ### Switch a job off -A setting can switch a job off, and **a job that's off isn't listed**. [Settings](/guides/settings#every-environment-setting) gives the switch for most jobs, such as a blank `MARFA_HEARTBEAT_URL` or an interval or retention of `0`. Two switches aren't tied to their jobs there: +A setting can switch a housekeeping job off, and **one that is off is not listed**. A live configuration change that enables a job makes it available without restarting the server. A retention of `0` leaves its cleanup job listed but stops age-based expiry. -- `enrichment-sweep` is off when `MARFA_ENRICHMENT_ENABLED` is `false`. -- `grant-inactivity-retirement` is off when `MARFA_GRANT_INACTIVITY_DAYS` is `0`. - -The retentions that `audit-cleanup`, `trash-purge`, `event-log-cleanup` and `inbound-delivery-cleanup` read can also change while the server runs, in the [configuration](/guides/settings#change-settings-while-it-runs). +`heartbeat` needs a configured receiver and the effective `heartbeat_enabled` switch. `enrichment-sweep` is off when the effective `enrichment_enabled` switch is `false`. `blob-orphans`, `bulk-action-gc`, `dcr-client-cleanup`, `grant-inactivity-retirement` and `revoked-grant-purge` are off when the interval or retention that drives them is `0`. ## Run a housekeeping job now @@ -108,7 +105,13 @@ An item stays in the bin until it is purged. Left alone, `trash-purge` purges ea A purge deletes items and their history for good. To see what it would take first, add `--dry-run` to the CLI command, or `"dry_run": true` to the HTTP body. A dry run changes nothing. -To empty the bin now, purge every item whose state is `trashed`. A key needs the `items.purge` permission, and **the private socket can't do it**, because it carries no key. This dry run counts what a purge would take: +To empty the trash through the private socket, use the owner's summary operation. **Each call attempts up to 200 selected items** and returns the committed purge count, per-item failures and a cursor for the next batch. Continue with that cursor until none remains. If a write outcome is unknown, read the trash again before retrying. This also works from a recent owner browser session. + +```bash +marfa --socket /path/to/data/control/marfa.sock items trash empty --confirm PURGE +``` + +A key holding `items.purge` can instead queue a bulk action for every item whose state is `trashed`. This dry run counts what a purge would take: diff --git a/content/docs/guides/run-a-connector.mdx b/content/docs/guides/run-a-connector.mdx index 7a607828..93037472 100644 --- a/content/docs/guides/run-a-connector.mdx +++ b/content/docs/guides/run-a-connector.mdx @@ -87,6 +87,12 @@ marfa connectors list +## Check and manage it in the browser + +**The owner’s Connectors page** at `/auth/owner/connectors` lists registrations and their reported state. Open a connector to see its details, current problems and recent runs. “Failing” means its latest run failed; “Problems” means it reported an issue; “Not heard from” means it has not reported a heartbeat, run or registration for more than a day. Check the process where it runs for the cause. + +The detail page offers two actions that cannot be undone. **Clear saved state** makes its next run start from the beginning. **Remove connector** deletes its registration, runs, webhook endpoints and stored deliveries from Marfa. It does not stop the external process or revoke its key: stop that process where it runs and revoke the key separately if you no longer need it. The [connector contract](https://github.com/withmarfa/marfa/blob/main/conformance/spec/connectors.md) defines the management operations. + ## Exit codes A run with `--once` ends with one of these codes: diff --git a/content/docs/guides/settings.mdx b/content/docs/guides/settings.mdx index 40faf00d..3865dca3 100644 --- a/content/docs/guides/settings.mdx +++ b/content/docs/guides/settings.mdx @@ -1,9 +1,9 @@ --- title: Settings -description: Every setting of an instance, from the environment it starts with to the configuration it changes while it runs. +description: Set an instance’s startup environment and change its name, data rules and operating policies while it runs. --- -An instance has two places for settings. The **environment** is read once, when the server starts, and covers everything from where the database lives to how often each housekeeping job runs. The **configuration** at `/config` changes while the server runs: it holds the instance's display name, three enforcement levers and the retentions you're most likely to adjust. +An instance has two kinds of settings. Environment settings are read once, when the server starts, and cover everything from where the database lives to how often each housekeeping job runs. The configuration at `/config` changes while the server runs. It holds the instance name, three enforcement levers, retention windows, version policy, unused-app retirement, file extraction and reporting switches. Addresses and credentials remain startup settings. ## Set an environment setting @@ -64,9 +64,7 @@ Marfa accepts a name that doesn't resolve or answer in time, and checks it again ## Change settings while it runs -The configuration at `/config` takes effect at once, with no restart. A credential needs the `config.manage` permission to read, replace or update it. The owner needs no key, through the private socket or signed in to the instance in a browser, where the **General** page at `/auth/owner/general` changes the name and the five retentions. - -A field you haven't set is left out of the answer: +The configuration at `/config` **takes effect at once, with no restart**. Reading, replacing or updating it needs the `config.manage` permission; the owner, signed in or through the private socket, needs no key. It holds these fields, and a field you have not set is left out of the answer: @@ -79,10 +77,21 @@ A field you haven't set is left out of the answer: | `event_log_retention_hours` | `integer` | Hours Marfa keeps events for a stream to replay. Overrides `MARFA_EVENT_LOG_RETENTION_HOURS`. | | `inbound_handled_retention_days` | `integer` | Days Marfa keeps an inbound webhook delivery a connector has marked handled. Overrides `MARFA_INBOUND_HANDLED_RETENTION_DAYS`. | | `inbound_pending_retention_days` | `integer` | Days Marfa keeps an inbound webhook delivery no connector has handled. Overrides `MARFA_INBOUND_PENDING_RETENTION_DAYS`. | +| `version_recent_days` | `integer` | Days Marfa keeps every item version. Overrides `VERSION_RECENT_DAYS`. | +| `version_daily_snapshot_days` | `integer` | Days Marfa keeps daily versions. Must be at least `version_recent_days`. Overrides `VERSION_DAILY_SNAPSHOT_DAYS`. | +| `version_weekly_snapshot_days` | `integer` | Days Marfa keeps weekly versions. Must be at least `version_daily_snapshot_days`. Overrides `VERSION_WEEKLY_SNAPSHOT_DAYS`. | +| `version_max_versions` | `integer` | Maximum versions kept per item after time windows. Overrides `VERSION_MAX_VERSIONS`. | +| `grant_inactivity_days` | `integer` | Days before an unused app grant is retired. `0` disables retirement. Overrides `MARFA_GRANT_INACTIVITY_DAYS`. | +| `enrichment_enabled` | `boolean` | Whether Marfa extracts text and image dimensions from files. Overrides `MARFA_ENRICHMENT_ENABLED`. | +| `enrichment_ocr_enabled` | `boolean` | Whether file extraction reads text from images. Overrides `MARFA_ENRICHMENT_OCR_ENABLED`. | +| `error_reporting_enabled` | `boolean` | Whether Marfa sends error alerts and exception reports to configured receivers. Overrides `MARFA_ERROR_REPORTING_ENABLED`. | +| `heartbeat_enabled` | `boolean` | Whether Marfa sends scheduled requests to a configured heartbeat receiver. Overrides `MARFA_HEARTBEAT_ENABLED`. | -A retention you leave unset takes the environment setting's value, and **a retention of `0` keeps those records with no age limit**. +**A cleanup retention of `0` keeps those records with no age limit.** A zero version window is empty, and zero `grant_inactivity_days` disables retirement. A setting you leave unset takes its environment value. Version windows must increase from recent to daily to weekly; a type-specific version policy still takes precedence. + +**The owner can change these live settings in a browser.** The General page, at `/auth/owner/general`, sends only the settings you changed. Changes apply to future work without a restart; disabling a switch does not cancel work already in flight. A reporting switch needs its receiver configured in the environment. A new name takes effect on the next request. Marfa trims the name, and refuses an empty one, one over 200 Unicode code points, or one with a control or bidirectional formatting character. diff --git a/content/docs/guides/upgrade.mdx b/content/docs/guides/upgrade.mdx index 2e384334..d672df4e 100644 --- a/content/docs/guides/upgrade.mdx +++ b/content/docs/guides/upgrade.mdx @@ -1,9 +1,9 @@ --- title: Upgrade -description: Check whether a new build can open your database, and move data through an archive when its schema differs. +description: Check a new build against your database while keeping a way back to the build that wrote it. --- -A build **never upgrades a database in place**. It refuses a database whose schema differs from its own or that holds retired tables or settings. If a new build refuses your database, export your data with the build that holds it, start the new build on empty storage, and restore the archive there. +A build **never upgrades a database in place**. A build refuses a database whose schema differs from its own or that holds retired tables or settings. If a new build refuses your database, keep the previous build and its data. An archive from it may be refused by a different build, so check a restore on separate storage before deciding to switch. ## What a new build does with your database @@ -17,7 +17,7 @@ A build's version doesn't tell you whether its database differs, so **treat ever ## Move data to a different schema -Use these steps when the new build refuses your database. A build that accepts the existing schema can keep using the same storage. +Use these steps to test a move when the new build refuses your database. A build that accepts the existing schema can keep using the same storage. **Keep the old build, its data and its export until the new build has accepted and verified the restore.** An archive is guaranteed only for the build that wrote it. @@ -49,7 +49,7 @@ Claim it as you did the first, with `marfa --socket /srv/marfa/data/control/marf ### Restore the archive -Restore it as the owner, through the private socket of the new instance: +Try the restore as the owner, through the private socket of the new instance. **The new build may refuse an archive from the old build**, even when that archive is valid: ```bash marfa --socket /srv/marfa/data/control/marfa.sock restore marfa-archive.tar.gz @@ -76,7 +76,7 @@ Make your keys again, register your webhooks again, and set the configuration ag ## If the new build refuses the archive -Only the build that wrote an archive is sure to read it. If the new build refuses yours, it can't read it. A refused restore writes nothing, so the new instance is unchanged and the old build still holds your data: **keep running the old build until a build can read the archive**. +Only the build that wrote an archive is sure to read it. If the new build refuses yours, it cannot read it. Do not treat the archive as a migration path until the target build has accepted it and you have checked its contents. A refused restore writes nothing, so the new instance is unchanged and the old build still holds your data: **keep running the old build until a build can read the archive**. On Railway, [update the server](https://github.com/withmarfa/marfa/blob/main/deploy/railway.md#update-the-server) applies these steps: template updates are opt-in, and a rollback changes the deployment, not the database. From 385780c92917d61493c9d61970773d21ee333eeb Mon Sep 17 00:00:00 2001 From: August Cayzer Date: Wed, 21 Oct 2026 05:40:09 +0100 Subject: [PATCH 2/8] docs(guides): correct console job and audit guidance --- content/docs/(overview)/access.mdx | 2 +- content/docs/guides/audit-log.mdx | 8 +++++--- content/docs/guides/housekeeping.mdx | 17 ++++++++++++----- content/docs/guides/settings.mdx | 27 ++------------------------- 4 files changed, 20 insertions(+), 34 deletions(-) diff --git a/content/docs/(overview)/access.mdx b/content/docs/(overview)/access.mdx index cbd3e19e..1304a9a2 100644 --- a/content/docs/(overview)/access.mdx +++ b/content/docs/(overview)/access.mdx @@ -15,7 +15,7 @@ Three kinds of caller act on an instance: | A key | Sent with each request, as `Authorization: Bearer marfa_k1_…` | What it was made with | | An app | Signs in through OAuth, and sends its access token, `marfa_at_…` | What the owner approved | -**The owner can list item summaries, manage the trash, read item counts and export data through a browser session**, without making a key. A summary gives an item's ID, type, version, name, source and creation time, but no properties, metadata, history or edges. The Items page searches names, not item content. The Trash page also shows when and by whom an item was trashed, and can move, restore or purge items. Those writes require a sign-in from the last five minutes. Both listings apply the instance's source filtering; an owner browser session still cannot open an item's content. +**The owner can list item summaries, manage the trash, read item counts and export data through a browser session**, without making a key. An item summary gives its ID, name, source and creation time, but no properties, metadata, history or edges. The Items page searches names, not item content. Trash summaries also show type, version, deletion time and actor, and can move, restore or purge items. Those writes require a sign-in from the last five minutes. Both listings apply the instance's source filtering; an owner browser session still cannot open an item's content. Other item content operations need a key or an app token. If a request sends a credential alongside the owner's browser session, that credential alone decides its access. No key or app ever gets the owner's authority, whatever it holds. [Sign in as the owner](/guides/sign-in-as-the-owner) shows how the owner signs in, with a password or a passkey. diff --git a/content/docs/guides/audit-log.mdx b/content/docs/guides/audit-log.mdx index 424f95f8..d1d10973 100644 --- a/content/docs/guides/audit-log.mdx +++ b/content/docs/guides/audit-log.mdx @@ -31,14 +31,15 @@ Each entry holds these fields: | --- | --- | --- | | `id` | `string` | The entry's identifier. | | `created_at` | `string` | When Marfa recorded the entry, in UTC. | -| `key_id` | `string \| null` | Who acted: the ID of a key or an app's token, or null for a write of Marfa's own, such as a housekeeping job. | +| `actor` | `object \| null` | The recorded sign-in kind, ID and readable name; Marfa for server work, or null when the actor is unknown. | +| `key_id` | `string \| null` | The acting credential's ID, or null when no credential is recorded. | | `action` | `string` | What happened, such as `item.create` or `export.run`. | | `resource_type` | `string` | The kind of thing acted on, such as `item`, `key` or `config`. | | `resource_id` | `string \| null` | The ID of the thing acted on, or null where there is none. | | `client_ip` | `string \| null` | The address the request came from, or null where there is none. | | `details` | `object` | More about the action, depending on action. | -When the owner acts, `key_id` names the owner's authority rather than a key: `local:process` through the private socket, or `owner:` and the browser session when signed in. Behind a proxy or a tunnel, `client_ip` is the proxy's address unless the server is told which address to believe, as [Deploy](/guides/deploy#the-address) explains. +**Use `actor` to identify who acted.** For authenticated actions, its `kind`, `id` and `name` are captured at the time, so a later rename or removal does not change the entry. Server work has actor `{ "kind": "server", "id": "server", "name": "Marfa" }`. Older entries without a captured actor, and actions before authentication, have `actor: null`; do not infer a person from their `key_id`. Behind a proxy or a tunnel, `client_ip` is the proxy's address unless the server is told which address to believe, as [Deploy](/guides/deploy#the-address) explains. ## Read the log @@ -58,6 +59,7 @@ marfa audit --action item.create --limit 1 --json { "id": "01a16970-ceb8-7dc2-9619-9b8d17b41c1b", "created_at": "2026-10-23T15:46:03.066Z", + "actor": { "kind": "key", "id": "01a15f23-e1dd-7fac-850a-4f4f11a24b8a", "name": "Example key" }, "key_id": "01a15f23-e1dd-7fac-850a-4f4f11a24b8a", "action": "item.create", "resource_type": "item", @@ -118,7 +120,7 @@ The HTTP request is `GET /audit?resource_type=item&resource_id=`. `marfa audit` takes all seven filters. Use `--kind` for `kind` and `--query` for `q`. [The audit kinds](https://github.com/withmarfa/marfa/blob/main/conformance/spec/events.md#eventsaudit-kind) and [the search](https://github.com/withmarfa/marfa/blob/main/conformance/spec/events.md#eventsaudit-search) hold the rules. -**There is no filter for `key_id`**, so to see what one key did, read the entries and compare their `key_id`. +**There is no filter for `key_id`**, so to see what one key did, read the entries and compare their `key_id`. Use `actor` for the readable identity where it was recorded. A page holds 50 entries unless `limit` asks for up to 200. When more match, the answer carries a `next_cursor`: send it back as `cursor` (or `--cursor`) for the next page, and stop when it's `null`. **Marfa refuses a query key it doesn't know** with `400 validation_error`, so a misspelled filter never reads as one that matched everything. diff --git a/content/docs/guides/housekeeping.mdx b/content/docs/guides/housekeeping.mdx index e767e603..e03db6cd 100644 --- a/content/docs/guides/housekeeping.mdx +++ b/content/docs/guides/housekeeping.mdx @@ -63,9 +63,9 @@ Each run reports `moved` and `held` in `last_result`. `moved` includes items a c ### Switch a job off -A setting can switch a housekeeping job off, and **one that is off is not listed**. A live configuration change that enables a job makes it available without restarting the server. A retention of `0` leaves its cleanup job listed but stops age-based expiry. +**Jobs controlled by live configuration stay listed when switched off.** You can still run one on demand; it answers `200` without doing the disabled work. This includes `enrichment-sweep` when `enrichment_enabled` is false and `grant-inactivity-retirement` when its retention is `0`. Enabling either in [configuration](/guides/settings#change-settings-while-it-runs) starts its work without a restart. A retention of `0` likewise keeps a cleanup job registered but stops age-based expiry. -`heartbeat` needs a configured receiver and the effective `heartbeat_enabled` switch. `enrichment-sweep` is off when the effective `enrichment_enabled` switch is `false`. `blob-orphans`, `bulk-action-gc`, `dcr-client-cleanup`, `grant-inactivity-retirement` and `revoked-grant-purge` are off when the interval or retention that drives them is `0`. +`heartbeat` is registered when a receiver is configured at startup. Its live `heartbeat_enabled` switch controls whether a run sends a ping. **A machine-only setting can prevent a job from being registered at all**, as `MARFA_BLOB_CLEANUP_INTERVAL_MS=0` does for `blob-orphans`. Such a job is absent from the listing and a run request for it answers `404 housekeeping_job_not_found`. Check the listing for the jobs this instance has. ## Run a housekeeping job now @@ -97,7 +97,7 @@ Authorization: Bearer **A run that fails still answers `200`**, with `outcome` set to `error` and the reason in `error`. The listing then shows this run as the last one, and a run on demand never makes the next scheduled run later. -Marfa refuses `409 housekeeping_job_running` while a run of the same job is in progress. A job that's switched off, or a name it doesn't run, is refused `404 housekeeping_job_not_found`. [Run a housekeeping job](/api-reference/instance/runHousekeeping) lists every answer. +The server refuses `409 housekeeping_job_running` while a run of the same housekeeping job is already in progress, so try again when it finishes. A name it has not registered is refused `404 housekeeping_job_not_found`. [Run a housekeeping job](/api-reference/instance/runHousekeeping) lists every answer. ## Empty the bin @@ -105,12 +105,19 @@ An item stays in the bin until it is purged. Left alone, `trash-purge` purges ea A purge deletes items and their history for good. To see what it would take first, add `--dry-run` to the CLI command, or `"dry_run": true` to the HTTP body. A dry run changes nothing. -To empty the trash through the private socket, use the owner's summary operation. **Each call attempts up to 200 selected items** and returns the committed purge count, per-item failures and a cursor for the next batch. Continue with that cursor until none remains. If a write outcome is unknown, read the trash again before retrying. This also works from a recent owner browser session. +To empty the trash through the private socket, use the owner's summary operation. **Each call attempts up to 200 selected items** and returns the committed purge count, per-item failures and a cursor for the next batch. Send `--cursor` or the HTTP `cursor` query parameter with the returned value until `next_cursor` is `null`. If a write outcome is unknown, read the trash again before retrying. The owner can also empty it from a recent browser session. ```bash marfa --socket /path/to/data/control/marfa.sock items trash empty --confirm PURGE ``` +```http tab="HTTP" +POST /trash/empty +Cookie: +``` + +Continue a batch with `POST /trash/empty?cursor=`. The response reports `purged`, per-item `failures` and `next_cursor`. + A key holding `items.purge` can instead queue a bulk action for every item whose state is `trashed`. This dry run counts what a purge would take: @@ -150,7 +157,7 @@ A test server can move its clock forward, so you can watch `feed-expiry` act wit The hooks sit at `/_control/test` on the private socket only, so run these steps on the instance's machine. `GET /_control/test/clock` answers `offset_ms` and the server's `now`. `POST /_control/test/clock` with `{ "advance_ms": 172800000 }` moves the clock forward by that many milliseconds, never back, and everything that reads the time moves with it. `MARFA_TEST_CLOCK_OFFSET_MS` starts the clock that far ahead and needs `MARFA_TEST_HOOKS`. -A key runs the `marfa` commands, because the private socket refuses item operations, and the socket alone reaches the clock. +**Two authorities are in play**: a key runs `marfa types register`, `marfa items create` and the content listing below, while the private socket reaches the clock and owner summary operations. It does not authorize ordinary item content reads or writes. diff --git a/content/docs/guides/settings.mdx b/content/docs/guides/settings.mdx index 3865dca3..e6259e5e 100644 --- a/content/docs/guides/settings.mdx +++ b/content/docs/guides/settings.mdx @@ -64,34 +64,11 @@ Marfa accepts a name that doesn't resolve or answer in time, and checks it again ## Change settings while it runs -The configuration at `/config` **takes effect at once, with no restart**. Reading, replacing or updating it needs the `config.manage` permission; the owner, signed in or through the private socket, needs no key. It holds these fields, and a field you have not set is left out of the answer: - - - -| Field | Type | Description | -| --- | --- | --- | -| `name` | `string` | The instance's display name. Defaults to `Marfa`. | -| `enforcement` | `object` | The three [enforcement levers](#what-the-enforcement-levers-do): `strict_mode`, `source_allowlist` and `source_filter`. | -| `trash_retention_days` | `integer` | Days an item stays in the bin before Marfa purges it. Overrides `TRASH_RETENTION_DAYS`. | -| `audit_retention_days` | `integer` | Days Marfa keeps audit log entries and the history of outbound webhook deliveries. Overrides `AUDIT_RETENTION_DAYS`. | -| `event_log_retention_hours` | `integer` | Hours Marfa keeps events for a stream to replay. Overrides `MARFA_EVENT_LOG_RETENTION_HOURS`. | -| `inbound_handled_retention_days` | `integer` | Days Marfa keeps an inbound webhook delivery a connector has marked handled. Overrides `MARFA_INBOUND_HANDLED_RETENTION_DAYS`. | -| `inbound_pending_retention_days` | `integer` | Days Marfa keeps an inbound webhook delivery no connector has handled. Overrides `MARFA_INBOUND_PENDING_RETENTION_DAYS`. | -| `version_recent_days` | `integer` | Days Marfa keeps every item version. Overrides `VERSION_RECENT_DAYS`. | -| `version_daily_snapshot_days` | `integer` | Days Marfa keeps daily versions. Must be at least `version_recent_days`. Overrides `VERSION_DAILY_SNAPSHOT_DAYS`. | -| `version_weekly_snapshot_days` | `integer` | Days Marfa keeps weekly versions. Must be at least `version_daily_snapshot_days`. Overrides `VERSION_WEEKLY_SNAPSHOT_DAYS`. | -| `version_max_versions` | `integer` | Maximum versions kept per item after time windows. Overrides `VERSION_MAX_VERSIONS`. | -| `grant_inactivity_days` | `integer` | Days before an unused app grant is retired. `0` disables retirement. Overrides `MARFA_GRANT_INACTIVITY_DAYS`. | -| `enrichment_enabled` | `boolean` | Whether Marfa extracts text and image dimensions from files. Overrides `MARFA_ENRICHMENT_ENABLED`. | -| `enrichment_ocr_enabled` | `boolean` | Whether file extraction reads text from images. Overrides `MARFA_ENRICHMENT_OCR_ENABLED`. | -| `error_reporting_enabled` | `boolean` | Whether Marfa sends error alerts and exception reports to configured receivers. Overrides `MARFA_ERROR_REPORTING_ENABLED`. | -| `heartbeat_enabled` | `boolean` | Whether Marfa sends scheduled requests to a configured heartbeat receiver. Overrides `MARFA_HEARTBEAT_ENABLED`. | - - +The configuration at `/config` **takes effect at once, with no restart**. Reading, replacing or updating it needs the `config.manage` permission; the owner, signed in or through the private socket, needs no key. [Read the configuration](/api-reference/instance/getConfig) lists every field and its type. A field you have not set is left out of the answer. **A cleanup retention of `0` keeps those records with no age limit.** A zero version window is empty, and zero `grant_inactivity_days` disables retirement. A setting you leave unset takes its environment value. Version windows must increase from recent to daily to weekly; a type-specific version policy still takes precedence. -**The owner can change these live settings in a browser.** The General page, at `/auth/owner/general`, sends only the settings you changed. Changes apply to future work without a restart; disabling a switch does not cancel work already in flight. A reporting switch needs its receiver configured in the environment. +**The owner can change the name, retention and version windows, unused-app retirement, file extraction and reporting switches in a browser.** The General page, at `/auth/owner/general`, sends only the settings you changed. Use the configuration API or CLI for the enforcement levers. Changes apply to future work without a restart; disabling a switch does not cancel work already in flight. A reporting switch needs its receiver configured in the environment. A new name takes effect on the next request. Marfa trims the name, and refuses an empty one, one over 200 Unicode code points, or one with a control or bidirectional formatting character. From ce671c6902b0a487db473dddf73c5793c7295f5a Mon Sep 17 00:00:00 2001 From: August Cayzer Date: Wed, 21 Oct 2026 05:46:21 +0100 Subject: [PATCH 3/8] docs(guides): group trash examples by client --- content/docs/guides/housekeeping.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/guides/housekeeping.mdx b/content/docs/guides/housekeeping.mdx index e03db6cd..d2a1f32b 100644 --- a/content/docs/guides/housekeeping.mdx +++ b/content/docs/guides/housekeeping.mdx @@ -107,7 +107,7 @@ An item stays in the bin until it is purged. Left alone, `trash-purge` purges ea To empty the trash through the private socket, use the owner's summary operation. **Each call attempts up to 200 selected items** and returns the committed purge count, per-item failures and a cursor for the next batch. Send `--cursor` or the HTTP `cursor` query parameter with the returned value until `next_cursor` is `null`. If a write outcome is unknown, read the trash again before retrying. The owner can also empty it from a recent browser session. -```bash +```bash tab="CLI" tab-group="client" marfa --socket /path/to/data/control/marfa.sock items trash empty --confirm PURGE ``` From 1406039642ac251af0a2b61cc778a8e80b7f6d72 Mon Sep 17 00:00:00 2001 From: August Cayzer Date: Wed, 21 Oct 2026 05:55:47 +0100 Subject: [PATCH 4/8] docs(guides): make owner request examples runnable --- content/docs/guides/export-and-restore.mdx | 2 +- content/docs/guides/housekeeping.mdx | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/content/docs/guides/export-and-restore.mdx b/content/docs/guides/export-and-restore.mdx index 4863ca2f..431cb17d 100644 --- a/content/docs/guides/export-and-restore.mdx +++ b/content/docs/guides/export-and-restore.mdx @@ -120,7 +120,7 @@ The manifest then names every file under `missing_blobs`, and a restore reports A restore **adds what the instance lacks and replaces nothing**. An item the instance already holds is counted in `duplicates` and left as it is, so replaying an archive never overwrites work done since. The target can be a new instance or the one the archive came from. -**Only the owner can restore**, through the private socket or signed in to the instance within the five minutes before the restore starts. A key is refused `403 forbidden`, whatever it holds. +**Only the owner can restore**, through the private socket or signed in to the instance within the five minutes before the restore starts. A key is refused `403 forbidden`, whatever it holds. Before using `--socket`, unset `MARFA_API_URL` and `MARFA_API_KEY` in that shell. ```bash marfa --socket /srv/marfa/data/control/marfa.sock restore marfa-archive.tar.gz diff --git a/content/docs/guides/housekeeping.mdx b/content/docs/guides/housekeeping.mdx index d2a1f32b..257119cb 100644 --- a/content/docs/guides/housekeeping.mdx +++ b/content/docs/guides/housekeeping.mdx @@ -108,11 +108,12 @@ An item stays in the bin until it is purged. Left alone, `trash-purge` purges ea To empty the trash through the private socket, use the owner's summary operation. **Each call attempts up to 200 selected items** and returns the committed purge count, per-item failures and a cursor for the next batch. Send `--cursor` or the HTTP `cursor` query parameter with the returned value until `next_cursor` is `null`. If a write outcome is unknown, read the trash again before retrying. The owner can also empty it from a recent browser session. ```bash tab="CLI" tab-group="client" -marfa --socket /path/to/data/control/marfa.sock items trash empty --confirm PURGE +env -u MARFA_API_URL -u MARFA_API_KEY marfa --socket /path/to/data/control/marfa.sock items trash empty --confirm PURGE ``` ```http tab="HTTP" POST /trash/empty +Origin: https://marfa.example.com Cookie: ``` From e55f86f20564c98594d3a276df351eab7df02482 Mon Sep 17 00:00:00 2001 From: August Cayzer Date: Wed, 21 Oct 2026 16:37:47 +0100 Subject: [PATCH 5/8] docs(guides): integrate console guidance with current page layout --- content/docs/(overview)/access.mdx | 4 +++- content/docs/guides/housekeeping.mdx | 2 +- content/docs/guides/run-a-connector.mdx | 4 +++- content/docs/guides/settings.mdx | 8 +++++--- content/docs/guides/upgrade.mdx | 2 +- 5 files changed, 13 insertions(+), 7 deletions(-) diff --git a/content/docs/(overview)/access.mdx b/content/docs/(overview)/access.mdx index 1304a9a2..716efaa9 100644 --- a/content/docs/(overview)/access.mdx +++ b/content/docs/(overview)/access.mdx @@ -15,7 +15,9 @@ Three kinds of caller act on an instance: | A key | Sent with each request, as `Authorization: Bearer marfa_k1_…` | What it was made with | | An app | Signs in through OAuth, and sends its access token, `marfa_at_…` | What the owner approved | -**The owner can list item summaries, manage the trash, read item counts and export data through a browser session**, without making a key. An item summary gives its ID, name, source and creation time, but no properties, metadata, history or edges. The Items page searches names, not item content. Trash summaries also show type, version, deletion time and actor, and can move, restore or purge items. Those writes require a sign-in from the last five minutes. Both listings apply the instance's source filtering; an owner browser session still cannot open an item's content. +Through a **browser session**, the owner can list item summaries, manage the trash, read item counts and export data without making a key. An item summary gives its ID, name, source and creation time, but no properties, metadata, history or edges. The **Items** page searches names, not item content. + +Trash summaries also show type, version, deletion time and actor. The **Trash** page can move, restore or purge items. Those writes require a sign-in from the last five minutes. Both listings apply the instance's source filtering; an owner browser session still cannot open an item's content. Other item content operations need a key or an app token. If a request sends a credential alongside the owner's browser session, that credential alone decides its access. No key or app ever gets the owner's authority, whatever it holds. [Sign in as the owner](/guides/sign-in-as-the-owner) shows how the owner signs in, with a password or a passkey. diff --git a/content/docs/guides/housekeeping.mdx b/content/docs/guides/housekeeping.mdx index 257119cb..c6161e17 100644 --- a/content/docs/guides/housekeeping.mdx +++ b/content/docs/guides/housekeeping.mdx @@ -103,7 +103,7 @@ The server refuses `409 housekeeping_job_running` while a run of the same housek An item stays in the bin until it is purged. Left alone, `trash-purge` purges each item once it has been in the bin longer than `TRASH_RETENTION_DAYS`, which is 60 days unless you change it. `trash_retention_days` in the [configuration](/guides/settings#change-settings-while-it-runs) overrides that while the server runs, and a retention of `0` keeps every item. A run removes a limited number of items, and while items past the retention remain after a run that removed some, the job runs again at once. -A purge deletes items and their history for good. To see what it would take first, add `--dry-run` to the CLI command, or `"dry_run": true` to the HTTP body. A dry run changes nothing. +A purge deletes items and their history for good. The owner’s empty-trash operation has no dry run. Read the trash before purging it. To empty the trash through the private socket, use the owner's summary operation. **Each call attempts up to 200 selected items** and returns the committed purge count, per-item failures and a cursor for the next batch. Send `--cursor` or the HTTP `cursor` query parameter with the returned value until `next_cursor` is `null`. If a write outcome is unknown, read the trash again before retrying. The owner can also empty it from a recent browser session. diff --git a/content/docs/guides/run-a-connector.mdx b/content/docs/guides/run-a-connector.mdx index 93037472..920156d5 100644 --- a/content/docs/guides/run-a-connector.mdx +++ b/content/docs/guides/run-a-connector.mdx @@ -87,9 +87,11 @@ marfa connectors list +To keep it running, start it with `--every 15m` in place of `--once`, which reads every feed every 15 minutes, or run `--once` from cron or launchd. The connector keeps no file: its place in each feed is on the instance, so a new process or container carries on from the last run. The repository's template README shows a launchd file and a container image. + ## Check and manage it in the browser -**The owner’s Connectors page** at `/auth/owner/connectors` lists registrations and their reported state. Open a connector to see its details, current problems and recent runs. “Failing” means its latest run failed; “Problems” means it reported an issue; “Not heard from” means it has not reported a heartbeat, run or registration for more than a day. Check the process where it runs for the cause. +The owner's **Connectors** page at `/auth/owner/connectors` lists registrations and their reported state. Open a connector to see its details, current problems and recent runs. **Failing** means its latest run failed; **Problems** means it reported an issue; **Not heard from** means it has not reported a heartbeat, run or registration for more than a day. Check the process where it runs for the cause. The detail page offers two actions that cannot be undone. **Clear saved state** makes its next run start from the beginning. **Remove connector** deletes its registration, runs, webhook endpoints and stored deliveries from Marfa. It does not stop the external process or revoke its key: stop that process where it runs and revoke the key separately if you no longer need it. The [connector contract](https://github.com/withmarfa/marfa/blob/main/conformance/spec/connectors.md) defines the management operations. diff --git a/content/docs/guides/settings.mdx b/content/docs/guides/settings.mdx index e6259e5e..8e65a4ae 100644 --- a/content/docs/guides/settings.mdx +++ b/content/docs/guides/settings.mdx @@ -3,7 +3,9 @@ title: Settings description: Set an instance’s startup environment and change its name, data rules and operating policies while it runs. --- -An instance has two kinds of settings. Environment settings are read once, when the server starts, and cover everything from where the database lives to how often each housekeeping job runs. The configuration at `/config` changes while the server runs. It holds the instance name, three enforcement levers, retention windows, version policy, unused-app retirement, file extraction and reporting switches. Addresses and credentials remain startup settings. +An instance has two places for settings. The **environment** is read once, when the server starts, and cover everything from where the database lives to how often each housekeeping job runs. The **configuration** at `/config` changes while the server runs. + +It holds the instance name, three enforcement levers, retention windows, version policy, unused-app retirement, file extraction and reporting switches. Addresses and credentials remain startup settings. ## Set an environment setting @@ -66,9 +68,9 @@ Marfa accepts a name that doesn't resolve or answer in time, and checks it again The configuration at `/config` **takes effect at once, with no restart**. Reading, replacing or updating it needs the `config.manage` permission; the owner, signed in or through the private socket, needs no key. [Read the configuration](/api-reference/instance/getConfig) lists every field and its type. A field you have not set is left out of the answer. -**A cleanup retention of `0` keeps those records with no age limit.** A zero version window is empty, and zero `grant_inactivity_days` disables retirement. A setting you leave unset takes its environment value. Version windows must increase from recent to daily to weekly; a type-specific version policy still takes precedence. +**A cleanup retention of `0` keeps those records with no age limit.** A zero version window is empty, and zero `grant_inactivity_days` disables retirement. A setting you leave unset takes its environment value. Version windows must not decrease from recent to daily to weekly; a type-specific version policy still takes precedence. -**The owner can change the name, retention and version windows, unused-app retirement, file extraction and reporting switches in a browser.** The General page, at `/auth/owner/general`, sends only the settings you changed. Use the configuration API or CLI for the enforcement levers. Changes apply to future work without a restart; disabling a switch does not cancel work already in flight. A reporting switch needs its receiver configured in the environment. +The owner can change the name, retention and version windows, unused-app retirement, file extraction and reporting switches on the **General** page, at `/auth/owner/general`. It sends only the settings you changed. Use the configuration API or CLI for the enforcement levers. Changes apply to future work without a restart; disabling a switch does not cancel work already in flight. A reporting switch needs its receiver configured in the environment. A new name takes effect on the next request. Marfa trims the name, and refuses an empty one, one over 200 Unicode code points, or one with a control or bidirectional formatting character. diff --git a/content/docs/guides/upgrade.mdx b/content/docs/guides/upgrade.mdx index d672df4e..5ece200f 100644 --- a/content/docs/guides/upgrade.mdx +++ b/content/docs/guides/upgrade.mdx @@ -3,7 +3,7 @@ title: Upgrade description: Check a new build against your database while keeping a way back to the build that wrote it. --- -A build **never upgrades a database in place**. A build refuses a database whose schema differs from its own or that holds retired tables or settings. If a new build refuses your database, keep the previous build and its data. An archive from it may be refused by a different build, so check a restore on separate storage before deciding to switch. +A build **never upgrades a database in place**. It refuses a database whose schema differs from its own or that holds retired tables or settings. If a new build refuses your database, keep the previous build and its data. An archive from it may be refused by a different build, so check a restore on separate storage before deciding to switch. ## What a new build does with your database From a221f556afcc0cea5a07b3c0b2d16d624883c702 Mon Sep 17 00:00:00 2001 From: August Cayzer Date: Wed, 21 Oct 2026 17:11:40 +0100 Subject: [PATCH 6/8] docs(guides): refresh release affected owner and folder guidance --- content/docs/guides/authenticate.mdx | 4 ++-- content/docs/guides/define-a-type.mdx | 6 ++++-- content/docs/guides/deploy.mdx | 2 +- content/docs/guides/export-and-restore.mdx | 4 ++-- content/docs/guides/receive-webhooks.mdx | 4 ++-- content/docs/guides/sign-in-as-the-owner.mdx | 12 +++++++++--- content/docs/guides/sync-a-folder.mdx | 7 ++++--- content/docs/guides/troubleshooting.mdx | 2 +- 8 files changed, 25 insertions(+), 16 deletions(-) diff --git a/content/docs/guides/authenticate.mdx b/content/docs/guides/authenticate.mdx index 133b7d52..776b5056 100644 --- a/content/docs/guides/authenticate.mdx +++ b/content/docs/guides/authenticate.mdx @@ -63,7 +63,7 @@ Content-Type: application/json Marfa answers `201` with the `client_id`. With `"token_endpoint_auth_method": "none"` the app proves itself with PKCE alone. Leave it out, and the answer also holds a `client_secret` to send with each token request. -Redirect addresses must use `https`, unless you also set `"application_type": "native"`, which allows an `http` loopback address such as `http://127.0.0.1:9000/callback`. [Register an OAuth client](/api-reference/access/registerOAuthClient) lists every field. +Redirect addresses must use `https`, unless you also set `"application_type": "native"`, which also allows an `http` loopback address or a reverse-domain private-use scheme with a path and no authority, such as `com.example.app:/callback`. [Register an OAuth client](/api-reference/access/registerOAuthClient) lists every field. @@ -217,7 +217,7 @@ token=marfa_rt_…&token_type_hint=refresh_token&client_id= Marfa answers `200`, even for a token it doesn't hold. -The owner can also disconnect an app on the **Connected apps** page, and revoke the keys the app made at the same time. A credential holding `grants.manage` lists apps with `GET /auth/grants` and ends one with `DELETE /auth/grants/{id}`. +The owner can narrow or disconnect an app on the **Connected apps** page. Narrowing ends tokens and refresh chains that exceed the remaining access; covered chains keep working. Increasing access requires fresh approval. When disconnecting, the owner can revoke the keys the app made at the same time. A credential holding `grants.manage` lists apps with `GET /auth/grants` and ends one with `DELETE /auth/grants/{id}`. Disconnecting from a browser **needs a sign-in from the last five minutes**, and the page asks the owner to [confirm it's them](/guides/sign-in-as-the-owner#confirm-its-you) if theirs is older. A program that sends the same request gets `403 forbidden`, and the app keeps working. A credential holding `grants.manage`, and the private local command, are not held to it. diff --git a/content/docs/guides/define-a-type.mdx b/content/docs/guides/define-a-type.mdx index 6ce5ecbc..d693f534 100644 --- a/content/docs/guides/define-a-type.mdx +++ b/content/docs/guides/define-a-type.mdx @@ -104,7 +104,7 @@ const { data, error } = await marfa.POST("/types", { }); ``` -Marfa answers `201` with the type as it stored it. It made the label `Receipt` from the identifier, and set the type's `version` to 0. That version is **yours to keep**: Marfa stores the number you send and never changes it. +Marfa answers `201` with the type as it stored it. Its `provenance` records who registered it; replacement keeps that creator. A creator that was never recorded stays unknown. It made the label `Receipt` from the identifier, and set the type's `version` to 0. That version is **yours to keep**: Marfa stores the number you send and never changes it. ```json { @@ -296,9 +296,11 @@ await marfa.DELETE("/types/{id}", { Marfa refuses to delete a type that another type names as its parent, with `409 type_has_subtypes`, and one that items still hold, in any state and the bin included, with `409 type_in_use`. A type that other types name in `compatible_with` is refused as [described above](#make-it-readable-as-another-type). -`force=true` (the CLI's `--force`) deletes a type that items still hold. It doesn't override a subtype or a `compatible_with` claim. The items stay, but until the type is registered again, Marfa refuses any write to their properties, tier or time, so they can't be edited. You can still tag, archive or move them to the bin. +`force=true` (the CLI's `--force`), sent with an authorized key, deletes a type that items still hold. It doesn't override a subtype or a `compatible_with` claim. The items stay, but until the type is registered again, Marfa refuses any write to their properties, tier or time, so they can't be edited. You can still tag, archive or move them to the bin. +The owner can also remove an **unused custom type** from the Items page, through a recent browser session or the private socket. The same item and dependency checks apply, and direct owner authority cannot use `force=true`. + ## What your key needs Each operation needs a key whose type map grants write on the type's identifier, plus a grant of its own: diff --git a/content/docs/guides/deploy.mdx b/content/docs/guides/deploy.mdx index 7e5e1cd4..157e0cdc 100644 --- a/content/docs/guides/deploy.mdx +++ b/content/docs/guides/deploy.mdx @@ -58,7 +58,7 @@ A command run on the same machine, as the account that runs the server, reaches marfa --socket /srv/marfa/data/control/marfa.sock setup open ``` -The CLI refuses `--socket` while `MARFA_API_URL` or `MARFA_API_KEY` is set. **The socket carries no key, so the server refuses operations on your data**, such as items, types and search, with `401 unauthorized` ([`device/local-socket-needs-key`](https://github.com/withmarfa/marfa/blob/main/conformance/spec/device.md#devicelocal-socket-needs-key)). Run those with a key. +The CLI refuses `--socket` while `MARFA_API_URL` or `MARFA_API_KEY` is set. **The socket carries no key, so item content, search, counts, events and exports need a credential**. Owner summaries, trash management and deletion of unused custom types remain available through the socket; ordinary content requests are refused with `401 unauthorized` ([`device/local-socket-needs-key`](https://github.com/withmarfa/marfa/blob/main/conformance/spec/device.md#devicelocal-socket-needs-key)). Run those with a key. The socket's folder must belong to the server's account and be readable by no one else. On Linux, install the `acl` package, which the server uses to check this. A start replaces a socket that a crash left behind, and refuses one that another process listens on ([`instance/control-live-refused`](https://github.com/withmarfa/marfa/blob/main/conformance/spec/instance.md#instancecontrol-live-refused)): find that process before you remove the socket. diff --git a/content/docs/guides/export-and-restore.mdx b/content/docs/guides/export-and-restore.mdx index 431cb17d..ebfb4f25 100644 --- a/content/docs/guides/export-and-restore.mdx +++ b/content/docs/guides/export-and-restore.mdx @@ -3,11 +3,11 @@ title: Export and restore an archive description: Export your items, edges, types and files to an archive, and restore it into the same instance or another, such as a new build. --- -An archive carries your content to another instance and leaves the instance's own setup behind: **no keys, webhooks, configuration or audit log**. It's how you move data to a new build when you [upgrade](/guides/upgrade). It **isn't a long-term backup**, because only the build that wrote it is sure to read it ([`search-and-filters/restore-version`](https://github.com/withmarfa/marfa/blob/main/conformance/spec/search-and-filters.md#search-and-filtersrestore-version)). To recover this instance from a failed disk, [back up the data directory](/guides/back-up-and-restore) instead. +An archive carries your content to another instance and leaves the instance's own setup behind: **no keys, webhooks, configuration or audit log**. Before moving data to a different build, [test a restore on fresh storage](/guides/upgrade); that build may refuse the archive. It **isn't a long-term backup**, because only the build that wrote it is sure to read it ([`search-and-filters/restore-version`](https://github.com/withmarfa/marfa/blob/main/conformance/spec/search-and-filters.md#search-and-filtersrestore-version)). To recover this instance from a failed disk, [back up the data directory](/guides/back-up-and-restore) instead. ## Export an archive -An archive holds what its caller can read. The owner **reads everything**, and exports from a browser without a key. The Export and restore page, at `/auth/owner/export`, downloads an archive of everything, or of one type and the types under it. The trash is never in it. To export from a script, use a key that reads every type, edge type and extension and holds `blobs.manage`. **Without `blobs.manage`, the archive leaves out the contents of files that only an earlier version names**, and its manifest doesn't list them as missing. +An archive holds what its caller can read. The owner exports from a browser without a key, subject to the instance's source filter. The Export and restore page, at `/auth/owner/export`, downloads an archive of everything, or of one type and the types under it. The trash is never in it. To export from a script, use a key that reads every type, edge type and extension and holds `blobs.manage`. **Without `blobs.manage`, the archive leaves out the contents of files that only an earlier version names**, and its manifest doesn't list them as missing. diff --git a/content/docs/guides/receive-webhooks.mdx b/content/docs/guides/receive-webhooks.mdx index c0e81d60..22f55228 100644 --- a/content/docs/guides/receive-webhooks.mdx +++ b/content/docs/guides/receive-webhooks.mdx @@ -5,7 +5,7 @@ description: Register a webhook, check that each delivery came from your instanc A webhook lets a service react to changes in your instance without holding a connection open: you register a URL, and Marfa posts each event you chose to it as it happens. [Events and webhooks](/events) explains when to use a webhook rather than the event stream. -You need a credential with the `webhooks.manage` permission. The webhook belongs to that key, or to the app that registered it: Marfa sends it nothing once the key is revoked or expires, and deletes it when the app's access is revoked. +To register or change a webhook, you need its maker’s credential with the `webhooks.manage` permission. The owner can inspect subscriptions and delivery metadata on the **API keys** and **Connected apps** detail pages, without reading event payloads or making a key. Retrying a failed delivery there needs a sign-in from the last five minutes; the private socket needs none. The webhook belongs to that key, or to the app that registered it: Marfa sends it nothing once the key is revoked or expires, and deletes it when the app's access is revoked. ## Register a webhook @@ -225,7 +225,7 @@ await marfa.POST("/webhooks/{id}/deliveries/{delivery_id}/redeliver", { }); ``` -Only a `dead_letter` delivery can be sent again; any other answers `409 conflict`. A delivery's record is kept for as long as the instance keeps its audit log. +Only a retained `dead_letter` delivery can be sent again, while its subscription is active and its maker still has the required access. This holds for an owner's retry too. A `409 conflict` carries the reason in `details.reason`; [Redeliver a failed delivery](/api-reference/webhooks/redeliverWebhookDelivery) lists the refusals. A delivery's record is kept for as long as the instance keeps its audit log. ## Change what a webhook sends diff --git a/content/docs/guides/sign-in-as-the-owner.mdx b/content/docs/guides/sign-in-as-the-owner.mdx index ef9981f2..0474dcb3 100644 --- a/content/docs/guides/sign-in-as-the-owner.mdx +++ b/content/docs/guides/sign-in-as-the-owner.mdx @@ -35,8 +35,9 @@ The list gives each sign-in's ID, kind, name and last use. A browser can't be re When your sign-in is older than five minutes, these changes show a **Confirm it's you** dialog that asks for the owner's password or a passkey, then send the change again: - Adding, renaming or removing a passkey. -- Changing the owner's name or email on the **Profile** page. -- Revoking a key, disconnecting an app, renaming a sign-in or signing out another browser. +- Changing the owner's name, email or picture address on the **Profile** page. +- Revoking a key, narrowing or disconnecting an app, renaming a sign-in or signing out another browser. +- Moving, restoring or purging items through **Trash**, removing an unused custom type, retrying a webhook delivery, or restoring an archive. - [Approving a write or a permission](/access#what-the-owner-approves) the app doesn't already hold. Confirming replaces your browser session with a new one. A wrong password answers `401 unauthorized`, and after too many attempts `429 rate_limited` with `Retry-After`. A passkey still confirms. A refused confirmation leaves your session as it was. @@ -52,8 +53,11 @@ Open the instance's address in a browser signed in as the owner, and Home lists | Access | [API keys](/guides/manage-keys#use-the-api-keys-page) | `/auth/owner/keys` | | Access | [Connected apps](/guides/authenticate#revoke-access) | `/auth/owner/apps` | | Access | [Browsers](#manage-passkeys-and-sign-ins) | `/auth/owner/browsers` | +| Your data | [Items](/access) | `/auth/owner/items` | +| Your data | [Trash](/guides/housekeeping#empty-the-bin) | `/auth/owner/trash` | | Your data | [Export and restore](/guides/export-and-restore) | `/auth/owner/export` | | Connections | [Connectors](/connectors) | `/auth/owner/connectors` | +| Connections | [Folders](/devices#folders) | `/auth/owner/folders` | | This Marfa | [General](/guides/settings#change-settings-while-it-runs) | `/auth/owner/general` | | This Marfa | [Health](/guides/housekeeping) | `/auth/owner/health` | | This Marfa | [Activity](/guides/audit-log) | `/auth/owner/activity` | @@ -61,6 +65,8 @@ Open the instance's address in a browser signed in as the owner, and Home lists | You | [Profile](#change-the-owners-profile) | `/auth/owner/profile` | | You | [Password and passkeys](#manage-passkeys-and-sign-ins) | `/auth/owner/passkeys` | +**Needs attention** on Home shows known health, job, connector and folder problems and keys nearing expiry. If a check fails, it is shown as unavailable rather than as healthy. The **Folders** pages show reported working copies and historical sign-ins; a recent report does not prove that a computer is online. + Opening an owner page without a session answers `302` to `/auth/sign-in` with the page as `return_to`, or to `/setup` when there is no owner yet. A program, one that sends `Authorization` or doesn't ask for HTML, gets no redirect. ## Change the owner's profile @@ -71,7 +77,7 @@ Only the owner changes the sign-in email: marfa --socket /srv/marfa/data/control/marfa.sock owner update --email owner@example.com --name "Reader" ``` -In a browser, the **Profile** page uses [Update the owner](/api-reference/access/updateOwner). The email is stored in lowercase, needs no confirmation and becomes the address for password sign-in. Everything else the owner holds stays in place. +In a browser, the **Profile** page uses [Update the owner](/api-reference/access/updateOwner). Under **Picture**, choose **Change** to set an HTTP(S) picture address, or leave it blank to clear it. Marfa stores the address, not an uploaded picture. The email is stored in lowercase, needs no confirmation and becomes the address for password sign-in. Everything else the owner holds stays in place. A key or an app with profile write access changes only the owner's **name or avatar**, with `marfa profile update --name "Reader"` or [Update the profile](/api-reference/access/updateProfile). **Email is never writable this way.** [Permissions](/catalog/permissions#access-to-profile-fields) lists the levels. diff --git a/content/docs/guides/sync-a-folder.mdx b/content/docs/guides/sync-a-folder.mdx index 8adb1f5a..75eaea11 100644 --- a/content/docs/guides/sync-a-folder.mdx +++ b/content/docs/guides/sync-a-folder.mdx @@ -75,7 +75,7 @@ the first sync will write and send nothing until you confirm it: 2 file(s) to wr **Nothing is written into the directory or sent to the instance until you confirm the first sync.** Here the instance holds two notes and the directory held one file, `Ideas.md`. At a terminal the command asks first; in a script, pass `--yes` to confirm at once. -Where an item's file would land on a file already there, one of the two gets a number added to its name, and **neither is written over**. A directory inside a folder you already added, or around one, is refused. +Where an item's file would land on a file the folder will send, one of the two gets a number added to its name, and **neither is written over**. If the existing file is held back, the plan counts the item as `left`, not as written beside it; that file stays for you to fix. A directory inside a folder you already added, or around one, is refused. Keep the directory out of iCloud Drive, other cloud-synced folders and network storage: two programs syncing the same files can overwrite each other's changes. `marfa folders add` warns and goes on. @@ -128,7 +128,8 @@ Start with the essays, then the letters. The lines between the `---` fences are the frontmatter. The text after them is the body. -- **`type`, `tier`, `tags`, `state` and `occurred_at`:** the item's own fields. +- **`type`:** the item’s type when the value is a Marfa type identifier. A value that is not a type identifier belongs to the item’s `type` property instead and survives writing the file back. +- **`tier`, `tags`, `state` and `occurred_at`:** the item’s own fields. - **A line named after an edge type,** such as `references`: an edge. - **Every other line:** a property. - **`marfa_id` and `marfa_version`:** the item and the version the file was written from. Leave them to Marfa. @@ -188,7 +189,7 @@ defaults: A new key with the same `--source` is refused `409 conflict` while the old key is live. [Revoke the old key](/guides/manage-keys#revoke-a-key), run the `keys create` command from the first step again, then run `marfa keys keep` so the folder reads the new key from the keychain. -Then run `marfa folders push Notes`. If the new key reads something other than the old one did, the instance refuses the folder's working copy and the push stops with `read_view_changed`. Run the push again: it builds the copy again itself, and its report starts with `hydrated 3 item(s) first`. Writes waiting in the queue are kept. +Then run `marfa folders push Notes`. If the key's read view changed, the push rebuilds the working copy once and sends the waiting writes in the same run, keeping earlier verdicts. If the view changes again during that run, the push stops and keeps the remaining writes queued. Try again once the key's access is settled. ## Stop following a folder diff --git a/content/docs/guides/troubleshooting.mdx b/content/docs/guides/troubleshooting.mdx index 23636b7d..47599929 100644 --- a/content/docs/guides/troubleshooting.mdx +++ b/content/docs/guides/troubleshooting.mdx @@ -52,7 +52,7 @@ Stop the other process, or set `PORT` to a free port. The database was written by a different build of Marfa. A build doesn't upgrade a database in place: it refuses the file and changes nothing in it, so the build that wrote it can still open it. -To move your data, export it with the old build and restore the archive into the new one. [Upgrade](/guides/upgrade) shows each step. +To test moving your data, export it with the old build and try restoring the archive into fresh storage with the new one. Keep the old build and database until you have checked the result; a different build may refuse the archive. [Upgrade](/guides/upgrade) shows each step. From df041b6f82ee9135cdb26ddf408abbac4e173d62 Mon Sep 17 00:00:00 2001 From: August Cayzer Date: Wed, 21 Oct 2026 17:14:20 +0100 Subject: [PATCH 7/8] docs(release): publish v0.0.21 changes and finish accuracy pass --- content/docs/(overview)/access.mdx | 4 ++-- content/docs/(reference)/changelog.mdx | 32 +++++++++++++++++++++++++- content/docs/(reference)/cli.mdx | 4 ++-- content/docs/guides/settings.mdx | 2 +- 4 files changed, 36 insertions(+), 6 deletions(-) diff --git a/content/docs/(overview)/access.mdx b/content/docs/(overview)/access.mdx index 716efaa9..5cf4c53a 100644 --- a/content/docs/(overview)/access.mdx +++ b/content/docs/(overview)/access.mdx @@ -15,9 +15,9 @@ Three kinds of caller act on an instance: | A key | Sent with each request, as `Authorization: Bearer marfa_k1_…` | What it was made with | | An app | Signs in through OAuth, and sends its access token, `marfa_at_…` | What the owner approved | -Through a **browser session**, the owner can list item summaries, manage the trash, read item counts and export data without making a key. An item summary gives its ID, name, source and creation time, but no properties, metadata, history or edges. The **Items** page searches names, not item content. +Through a **browser session**, the owner can list item summaries, manage the trash, read item counts and export data without making a key. An item summary gives its ID, type, version, name, source and creation time, but no properties, metadata, history or edges. The **Items** page searches names, not item content. -Trash summaries also show type, version, deletion time and actor. The **Trash** page can move, restore or purge items. Those writes require a sign-in from the last five minutes. Both listings apply the instance's source filtering; an owner browser session still cannot open an item's content. +Trash summaries also show the deletion time and actor. The **Trash** page can move, restore or purge items. Those writes require a sign-in from the last five minutes. Both listings apply the instance's source filtering; an owner browser session still cannot open an item's content. Other item content operations need a key or an app token. If a request sends a credential alongside the owner's browser session, that credential alone decides its access. No key or app ever gets the owner's authority, whatever it holds. [Sign in as the owner](/guides/sign-in-as-the-owner) shows how the owner signs in, with a password or a passkey. diff --git a/content/docs/(reference)/changelog.mdx b/content/docs/(reference)/changelog.mdx index 2d13972a..12562b19 100644 --- a/content/docs/(reference)/changelog.mdx +++ b/content/docs/(reference)/changelog.mdx @@ -5,7 +5,37 @@ description: What each release of Marfa changed for someone running an instance Each release of Marfa ships the server and its container image, the CLI for macOS on Apple silicon, and the TypeScript SDK on npm. This page lists every release, newest first, with what changed and a link to the full list on GitHub. The Swift SDK's own releases are listed after Marfa's. -**Marfa doesn't upgrade a database in place.** A build refuses a database whose schema differs from its own, or that holds retired tables or settings, and leaves the file unchanged; a version change alone doesn't cause a refusal. [Upgrade](/guides/upgrade) shows how to move your data with an export and a restore. +**Marfa doesn't upgrade a database in place.** A build refuses a database whose schema differs from its own, or that holds retired tables or settings, and leaves the file unchanged; a version change alone doesn't cause a refusal. [Upgrade](/guides/upgrade) shows how to test an export and restore on fresh storage before switching builds. + +## v0.0.21 + +Released October 21, 2026. [v0.0.21 on GitHub](https://github.com/withmarfa/marfa/releases/tag/v0.0.21) + +**This release changes the database schema.** It refuses an existing v0.0.20 database without changing it. Keep the old build, database and an export made with that build. Test restoring the export into fresh storage before replacing the running instance; cross-build restore is not guaranteed. [Upgrade](/guides/upgrade) covers the process. + +For the owner's console: + +- **Items and Trash work with summaries.** Items lists and searches names by type without opening item content. Names follow the type's display hints and fallback fields. Trash shows who moved an item there, when, and when it becomes eligible for deletion. You can move items to the trash, restore or permanently delete them, empty the trash in batches, and remove unused custom types. Item actions check the version you saw. These changes ask for a recent sign-in. +- **Connected apps lets you reduce access.** Saving a reduction ends tokens and refresh chains that exceed it; tokens already within the reduced access keep working. Increasing access requires fresh approval. The app-access operations are also published in the API reference. +- **Folders shows reported copies and their problems.** The list and detail pages separate current reports from historical sign-ins. A reported copy does not mean a computer is online. +- **Key and app pages show their webhooks and delivery history.** The owner can retry a retained failed delivery, subject to the subscription's current settings and its maker's access. Creating or changing a subscription still needs its maker's credential. +- **Activity and types retain names.** Audit entries keep the acting sign-in's name at the time of the action. Type details identify the creator where one is recorded; unknown history stays unknown. The CLI's audit command also filters by kind and text. +- **More settings take effect without a restart.** General can change version retention, unused-app retirement, file reading and OCR, error reporting and heartbeat reporting. Receiver addresses and credentials remain machine settings. +- **Home and the CLI share Needs attention.** Health, failed jobs, connector and folder problems, and keys nearing expiry come from one operation. A failed check appears as unavailable alongside any known concerns. +- **Profile accepts a picture address.** The owner can set or clear an HTTP(S) picture URL in Profile or through the CLI's owner update command. + +For running an instance and using the CLI: + +- **An unresponsive file store no longer holds work indefinitely.** Blob reads try another recorded copy when a store does not begin answering. Integrity and replication jobs report work they could not finish. An unfinished store write or deletion blocks conflicting operations on the same blob, and removing a copy confirms enough other copies still exist. +- **Private-socket access excludes item content.** Item properties, edges, tags, search, counts, events and exports need a key. Summaries and owner trash operations remain available through the socket. A refusal explains which access to use. +- **Sign-in and command errors give the relevant next step.** Login keeps polling through temporary server failures while its code remains valid. Connected apps distinguishes the Marfa CLI from other apps using device authorization. Setup-code refusals, an unreadable keychain, an unreachable server and webhook retry refusals carry more specific errors. + +For folders and app builders: + +- **A folder push recovers once from a changed key's read view.** It rebuilds the copy and continues waiting writes in the same run, keeping earlier verdicts. A watch preserves the server's requested wait when it hands a folder to a command and takes it back. +- **Folder reports distinguish waiting, unchanged and held files.** First-sync plans count files they leave in place separately from files written beside existing ones. A document the scan refuses is held with its reason, rather than described as waiting to send. +- **A frontmatter type value can belong to another notes app.** A value that is not a Marfa type identifier stays in the item's `type` property and survives writing the file back. A value shaped like a Marfa type identifier still selects the item's type and is refused if it cannot be used. +- **The core's Swift binding accepts a credential renewer.** Apps can provide renewal for working copies and folders when a token is refused, with queued writes retained on failure. This is a binding change in Marfa; the Swift SDK has its own release. ## v0.0.20 diff --git a/content/docs/(reference)/cli.mdx b/content/docs/(reference)/cli.mdx index a191e43a..7bb47f0b 100644 --- a/content/docs/(reference)/cli.mdx +++ b/content/docs/(reference)/cli.mdx @@ -145,13 +145,13 @@ That's how the owner makes the first key in the [Quickstart](/quickstart). These | --- | --- | --- | | `marfa setup status`, `setup code`, `setup open` | Check whether the instance is claimed, replace the setup code, and open the browser handoff. | [Quickstart](/quickstart) | | `marfa owner recover` | Set a new owner password. | [Sign in as the owner](/guides/sign-in-as-the-owner#recover-the-owners-password) | -| `marfa owner update` | Change the owner's email and name. | [Sign in as the owner](/guides/sign-in-as-the-owner#change-the-owners-profile) | +| `marfa owner update` | Change the owner's email, name and picture address. | [Sign in as the owner](/guides/sign-in-as-the-owner#change-the-owners-profile) | | `marfa owner passkeys` | Add, list, rename and remove passkeys. | [Sign in as the owner](/guides/sign-in-as-the-owner#manage-passkeys-and-sign-ins) | | `marfa items summaries` | List item summaries without opening item content. | [Access](/access#who-can-act) | | `marfa items trash` | List, move, restore and purge items in the trash. | [Housekeeping](/guides/housekeeping#empty-the-bin) | | `marfa sign-ins` | List, rename and end the sign-ins that can reach the server. | [Sign in as the owner](/guides/sign-in-as-the-owner#manage-passkeys-and-sign-ins) | -**The socket carries no key.** `--socket` can't be combined with `--url`, `--key`, `MARFA_API_URL` or `MARFA_API_KEY`. An operation that needs a key, such as `marfa events` or `marfa export`, ends with exit code 5, so run it with a key instead. `marfa login`, `logout`, `device`, `folders`, `docs` and `types scaffold` refuse `--socket`. +**The socket carries no key.** `--socket` can't be combined with `--url`, `--key`, `MARFA_API_URL` or `MARFA_API_KEY`. An operation that needs a key, such as `marfa events` or `marfa export`, ends with exit code 5, so run it with a key instead. `marfa login`, `logout`, `device`, `docs`, `types scaffold` and local folder commands refuse `--socket`. `marfa folders inventory` is the exception: it reads the owner’s reported folder copies through the socket. ## Exit codes diff --git a/content/docs/guides/settings.mdx b/content/docs/guides/settings.mdx index 8e65a4ae..65184dcb 100644 --- a/content/docs/guides/settings.mdx +++ b/content/docs/guides/settings.mdx @@ -3,7 +3,7 @@ title: Settings description: Set an instance’s startup environment and change its name, data rules and operating policies while it runs. --- -An instance has two places for settings. The **environment** is read once, when the server starts, and cover everything from where the database lives to how often each housekeeping job runs. The **configuration** at `/config` changes while the server runs. +An instance has two places for settings. The **environment** is read once, when the server starts, and covers everything from where the database lives to how often each housekeeping job runs. The **configuration** at `/config` changes while the server runs. It holds the instance name, three enforcement levers, retention windows, version policy, unused-app retirement, file extraction and reporting switches. Addresses and credentials remain startup settings. From d367f6e763c6a0d5ce1903daf550b9b7aebeb386 Mon Sep 17 00:00:00 2001 From: August Cayzer Date: Wed, 21 Oct 2026 17:19:02 +0100 Subject: [PATCH 8/8] docs(guides): clarify connector source actions --- content/docs/guides/run-a-connector.mdx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/content/docs/guides/run-a-connector.mdx b/content/docs/guides/run-a-connector.mdx index 920156d5..67bf083f 100644 --- a/content/docs/guides/run-a-connector.mdx +++ b/content/docs/guides/run-a-connector.mdx @@ -93,7 +93,12 @@ To keep it running, start it with `--every 15m` in place of `--once`, which read The owner's **Connectors** page at `/auth/owner/connectors` lists registrations and their reported state. Open a connector to see its details, current problems and recent runs. **Failing** means its latest run failed; **Problems** means it reported an issue; **Not heard from** means it has not reported a heartbeat, run or registration for more than a day. Check the process where it runs for the cause. -The detail page offers two actions that cannot be undone. **Clear saved state** makes its next run start from the beginning. **Remove connector** deletes its registration, runs, webhook endpoints and stored deliveries from Marfa. It does not stop the external process or revoke its key: stop that process where it runs and revoke the key separately if you no longer need it. The [connector contract](https://github.com/withmarfa/marfa/blob/main/conformance/spec/connectors.md) defines the management operations. +The detail page offers two actions that cannot be undone: + +- **Clear saved state** removes the state and agreements for that connector's source. If a replacement key has registered under the same source, this also clears its saved state. The source's next run starts from the beginning. +- **Remove connector** deletes the selected registration and its runs. It also deletes the source's webhook endpoints and retained deliveries if this is its current registration. Removing an older registration leaves the successor's endpoints and deliveries in place. + +Neither action stops the external process or revokes its key. Stop the process where it runs and revoke the key separately if you no longer need it. The [connector contract](https://github.com/withmarfa/marfa/blob/main/conformance/spec/connectors.md) and [inbound webhook contract](https://github.com/withmarfa/marfa/blob/main/conformance/spec/inbound-webhooks.md#inbound-webhookssource-old-delete-keeps) define the effects. ## Exit codes