diff --git a/cookbook/aws-secrets-sync.mdx b/cookbook/aws-secrets-sync.mdx
new file mode 100644
index 000000000..f09e74a0d
--- /dev/null
+++ b/cookbook/aws-secrets-sync.mdx
@@ -0,0 +1,263 @@
+---
+title: AWS Secrets Sync
+description: Sync AWS Secrets Manager values into OpenHands personal or organization secrets.
+icon: key
+---
+
+{/* GENERATED from OpenHands/enterprise-cookbook@main (aws-secrets-sync/README.md). Edit the source, not this file. */}
+
+
+
+A Python script you run on your own scheduler. It reads explicitly mapped AWS
+Secrets Manager values, writes them through OpenHands secrets APIs, and updates
+them when AWS rotates them. AWS is the working example: you can adapt the source
+reader to another secrets manager. Nothing is installed in OpenHands.
+
+## How It Works
+
+```mermaid
+sequenceDiagram
+ participant S as Scheduler
+ participant P as Sync script
+ participant J as SQLite journal
+ participant A as AWS Secrets Manager
+ participant O as OpenHands API
+ S->>P: Run with mapping and OH_API_KEY
+ P->>O: Verify key binding; list secret names
+ loop Each mapping
+ P->>J: Read checkpoint
+ P->>A: Describe AWSCURRENT version
+ alt Missing or authorized changed version, with --apply
+ P->>A: Read that exact version
+ opt Replacing a shared value
+ P->>J: Record delete_pending
+ P->>O: DELETE secret
+ P->>J: Record deleted after acknowledgment
+ end
+ P->>J: Record pending
+ P->>O: POST create or personal upsert
+ P->>J: Record applied after acknowledgment
+ end
+ end
+```
+
+The script creates missing entries, skips unchanged AWS versions, and updates
+changed versions only for mappings already owned by its journal. Unknown existing
+names or edited ARN/field mappings are refused; use a new destination name or
+[operator recovery](https://github.com/OpenHands/enterprise-cookbook/blob/main/aws-secrets-sync/RECOVERY.md). Source deletion and removed mappings never
+cause destination deletion.
+
+## Prerequisites
+
+- Python 3.10+ on Linux or macOS; `boto3` and `requests` from `requirements.txt`.
+- AWS credentials through the [Boto3 credential chain](https://docs.aws.amazon.com/boto3/latest/guide/credentials.html).
+ Grant `DescribeSecret` and `GetSecretValue` on the mapped ARNs; see the
+ [IAM example](https://github.com/OpenHands/enterprise-cookbook/blob/main/aws-secrets-sync/iam-policy.example.json) and [AWS access documentation](https://docs.aws.amazon.com/secretsmanager/latest/userguide/auth-and-access.html).
+ Customer-managed encryption keys may require `kms:Decrypt`.
+- An organization-bound OpenHands API key injected as `OH_API_KEY`. Shared-secret
+ writes require owner/admin permission. Keep credentials out of mappings and
+ command arguments. `GET /api/keys/current` returns organization and user IDs;
+ verify they match the intended account and organization before configuring them.
+
+## Run It
+
+From this directory, install dependencies:
+
+```bash
+python -m pip install -r requirements.txt
+```
+
+Set the mapping's HTTPS origin, organization UUID, exact AWS ARN, and destination
+name (a valid environment-variable name). `json_field` selects one top-level string
+field; omit it for the whole string. Binary values are unsupported.
+
+
+
+ Copy [mapping.example.json](https://github.com/OpenHands/enterprise-cookbook/blob/main/aws-secrets-sync/mapping.example.json) to `mapping.local.json` and
+ edit it. Use the same journal for preview, initial import, and recurring sync.
+
+ ```bash
+ python sync_secrets.py --config mapping.local.json --state .sync-state/org/journal.sqlite
+ ```
+
+ ```text
+ mapping 1: would create (value not read)
+ ```
+
+ ```bash
+ python sync_secrets.py --config mapping.local.json --state .sync-state/org/journal.sqlite --apply
+ ```
+
+ ```text
+ mapping 1: create acknowledged
+ ```
+
+ After the source version changes, run:
+
+ ```bash
+ python sync_secrets.py --config mapping.local.json --state .sync-state/org/journal.sqlite --sync --allow-delete-recreate --apply
+ ```
+
+ ```text
+ mapping 1: delete/recreate acknowledged
+ ```
+
+
+ This command deletes and re-creates shared values, including on newer servers.
+ If creation fails, the secret can remain missing for all members until recovery.
+ Read [Updates and Recovery](#updates-and-recovery) before scheduling it.
+
+
+
+
+ Copy [mapping.personal.example.json](https://github.com/OpenHands/enterprise-cookbook/blob/main/aws-secrets-sync/mapping.personal.example.json) to
+ `alice.local.json`. Supply the intended user's own org-bound key and
+ `expected_user_id`; an administrator key does not impersonate them. Use a separate
+ mapping and persistent journal for each user.
+
+ ```bash
+ python sync_secrets.py --config alice.local.json --state .sync-state/alice/journal.sqlite
+ ```
+
+ ```text
+ mapping 1: would create (value not read)
+ ```
+
+ ```bash
+ python sync_secrets.py --config alice.local.json --state .sync-state/alice/journal.sqlite --apply
+ ```
+
+ ```text
+ mapping 1: create acknowledged
+ ```
+
+ After the source version changes, run:
+
+ ```bash
+ python sync_secrets.py --config alice.local.json --state .sync-state/alice/journal.sqlite --sync --apply
+ ```
+
+ ```text
+ mapping 1: personal upsert acknowledged
+ ```
+
+
+
+Omit `--apply` to preview without reading values. Unchanged versions print:
+
+```text
+mapping 1: checkpoint unchanged (not value-verified)
+```
+
+Your scheduler can run the recurring command weekly with absolute paths, injected
+credentials, and the same persistent journal. Its directory must be private
+(`chmod 700`). Run one exclusive writer per destination and alert on any nonzero
+exit; successful mappings remain committed when another fails.
+
+## Secret Name Collisions
+
+On the tested API, personal secrets belong to a user within the effective
+organization. Personal and shared names are separate namespaces; neither create
+endpoint rejects a name used in the other scope. The personal value keeps the bare
+name; the shared value receives a suffix (`_2`, `_3`, …)
+in that user's conversations and `GET /api/v1/secrets/search`. The stored shared
+name remains unchanged in the organization listing.
+
+
+ An organization sync cannot see members' personal secrets. A member with a
+ matching personal name keeps their own value under that name; rotating the shared
+ value only changes their suffixed variable, such as `NAME_2`.
+
+
+Personal preflight rejects mapped names that match shared names as listed in the
+search results. A shared secret created later can appear already suffixed, so the
+next sync does **not** detect that base-name collision. Use team/system prefixes
+and reserve managed names across scopes; this script cannot enforce that policy.
+
+## Updates and Recovery
+
+Personal values use upsert. This recipe rotates shared values with DELETE then
+POST, only with `--sync --allow-delete-recreate`. It validates the new AWS value
+before deleting anything. The existing organization metadata PUT cannot replace
+values; the newer value-replacement API is separate (see [Compatibility](#compatibility)).
+
+
+ After DELETE succeeds, the shared entry is absent until POST succeeds. New
+ conversations started in that window lack the shared value. A failed or
+ unacknowledged POST can leave it missing for all members until an operator
+ completes [recovery](https://github.com/OpenHands/enterprise-cookbook/blob/main/aws-secrets-sync/RECOVERY.md); it is not just a brief availability gap.
+ A timeout can also hide a successful write. The script blocks uncertain mappings
+ instead of guessing or automatically retrying them.
+
+
+New conversations receive updated values; running conversations can retain old
+values. Credential revocation is a separate process. Keep exclusive control of
+managed names: the operations used here have no conditional-write contract, and
+the local journal lock cannot coordinate other clients. Out-of-band destination
+value changes are not detected.
+
+| Journal Status | Action |
+| ---------------------------- | --------------------------------------------------------------------------------------------------------- |
+| `applied` | Normal sync can continue |
+| `deleted` | Acknowledged shared deletion, no POST attempted; rerun the shared sync command to restore an absent entry |
+| `pending` / `delete_pending` | Uncertain outcome; follow operator recovery before resuming |
+
+A `deleted` checkpoint also blocks if the entry is unexpectedly present; reconcile
+it before proceeding. Do not erase the journal to bypass uncertainty. Values and
+tokens are not intentionally logged or stored in it; disable HTTP/SDK wire logging
+in your runner.
+
+## Adapt to Another Vault
+
+In [sync_secrets.py](https://github.com/OpenHands/enterprise-cookbook/blob/main/aws-secrets-sync/sync_secrets.py), replace `current_version()` and
+`read_value()` with your vault's metadata/version and value API calls. Adjust the
+client factory, ARN-to-region parsing in `sync()`, mapping validation, and source
+error handling. Keep a stable source ID and version token; read the exact requested
+version and fail safely if it changes between metadata and value reads.
+
+Keep the OpenHands adapters and journal for the destination side. Other vaults
+are extension points, not included integrations; qualify their authentication,
+versioning, retries, and synthetic-secret delivery before use.
+
+## APIs Used
+
+| Endpoint | Used For |
+| --------------------------------------------------- | -------------------------------------------------------- |
+| AWS `DescribeSecret` / `GetSecretValue` | Locate and read the exact `AWSCURRENT` version |
+| `GET /api/keys/current` | Verify effective/bound organization and personal user |
+| `GET /api/organizations/{org_id}/secrets` | List shared names |
+| `POST /api/organizations/{org_id}/secrets` | Create shared values |
+| `DELETE /api/organizations/{org_id}/secrets/{name}` | Remove the old shared entry before re-creation |
+| `GET /api/v1/secrets/search` | List personal/shared names visible to the user |
+| `POST /api/v1/secrets` | Create or upsert the authenticated user's personal value |
+
+## Compatibility
+
+The [maintainer review](https://github.com/OpenHands/enterprise-cookbook/pull/29#pullrequestreview-5689160630)
+validated this script at `2e83432` on **Enterprise 1.74.0**, using simulated AWS
+(moto) and real OpenHands APIs and agent consumption of rotated values. Qualify
+your deployment before importing real credentials; this is not a minimum-version
+or blanket compatibility guarantee.
+
+**Enterprise 1.81.0 added atomic shared-value replacement** through separate
+`GET .../secrets/{name}/version` and `PUT .../secrets/{name}/value` endpoints.
+This recipe does **not** use or qualify them and still deletes/re-creates shared
+values on newer servers. Adopting that API requires a separately tested adapter
+and conditional-version/retry handling; the ordinary metadata PUT remains
+metadata-only. Inspect your deployment's `/openapi.json` before choosing a path.
+
+## Related
+
+
+
+ Managing and using secrets
+
+
+
+ Exact version reads
+
+
+
+ A separate delivery scope
+
+
diff --git a/cookbook/index.mdx b/cookbook/index.mdx
index a2f4fbbb5..9b18ad0ea 100644
--- a/cookbook/index.mdx
+++ b/cookbook/index.mdx
@@ -67,6 +67,10 @@ Observe conversations and react to their state.
Inject credentials and manage identity.
+
+ Sync AWS Secrets Manager values into OpenHands personal or organization secrets.
+
+
Configure GPG commit signing on every conversation with a SessionStart hook that imports a key from a custom secret.
diff --git a/docs.json b/docs.json
index 7c7506766..b37f3efab 100644
--- a/docs.json
+++ b/docs.json
@@ -600,6 +600,7 @@
{
"group": "Secrets & authentication",
"pages": [
+ "cookbook/aws-secrets-sync",
"cookbook/gpg-commit-signing",
"cookbook/per-conversation-secrets",
"cookbook/service-account-github-pat"