{
  "schema": "aaes/capability-pack/1",
  "provider": "launchdarkly",
  "version": "1.0.0",
  "description": "Read LaunchDarkly projects and feature flags; create flags, change their settings or targeting, and delete flags or projects. Creation and targeting changes can immediately change application behavior.",
  "notes": "The endpoint host 'launchdarkly-api.invalid' is a reserved non-production placeholder (an RFC 2606 reserved TLD): substitute the customer's LaunchDarkly base URI before enabling — app.launchdarkly.com for commercial, app.eu.launchdarkly.com for the EU instance, app.launchdarkly.us for federal — in every endpoint, in the resource locator and in every egress allowlist entry. The allowlist matches exactly, so all three move together, and substitution is a required deployment step. PROJECT_KEY and FLAG_KEY in the endpoint paths are placeholders to bind before enabling.\n\nRisk classification: collection and single-resource reads sit at the minimum R0 tier; flag creation registers as create and deploy at the minimum R3 tier: creation is not guaranteed inert, because a newly existing flag's OFF variation can differ from the application's missing-flag fallback value, so creating a flag can change served behavior before any toggle or targeting.\n\nThe flag UPDATE endpoint (PATCH /api/v2/flags/{project}/{flag}) is registered once, as update and deploy at the minimum R3 tier: the endpoint accepts JSON patch, JSON merge patch and semantic patch bodies, and a semantic patch instruction such as turnFlagOn or turnFlagOff, addTargets or updateFallthroughVariationOrRollout changes what production software serves to end users immediately — toggling a feature flag in a production environment is a extensive, deploy-equivalent write, and deploy is one of the designated actions requiring human approval.\n\nRequest limits: because the same endpoint and method also performs benign settings edits (name, description, tags, maintainer) and the request body is an unrestricted patch document, a lower-tier registration would not cover all effects of this endpoint — an installer's intention to patch only settings is not a restriction the registration enforces, so this pack registers the endpoint once at R3 and does not offer a separate 'settings-only' capability.\n\nFlag deletion and project deletion sit at the minimum R3 tier as deletes. Provider-side controls, noted but not relied on: LaunchDarkly can require approvals for flag changes in an environment, in which case a direct API change fails with 405 and must go through an approval request — that is the provider's control, not this registration's, and this pack deliberately does not register the approvals API (creating or applying approval requests is approve-equivalent and needs its own review).\n\nAPI versioning: each access token is pinned to an API version at creation (tokens created before versioning are pinned to 20160426), and a request may override with the LD-API-Version header; this pack registers paths under /api/v2 and the deployment should confirm the token's pinned version serves them.\n\nDocumented exclusions: this pack does not register the access tokens API (token lifecycle is an external custody process — see the credential note), members/teams/custom-roles management (access-granting), the approvals API, segments management, environment creation/deletion, data export, relay proxy configuration, and webhooks/integrations. SDK keys, mobile keys and client-side IDs cannot call this REST API at all — a deployment must not store one under this pack's reference.",
  "credential": {
    "secret_ref_id": "secret-ref-launchdarkly-service-token",
    "custody": "customer_vault",
    "inject": "header",
    "inject_name": "Authorization",
    "note": "A LaunchDarkly service access token, held in the client's own secret manager. Token issuance is external: a team member with sufficient permissions creates the token on LaunchDarkly's Authorization page (or an integration admin provisions it), and the deployment's custody job stores it under this reference.\n\nStored-value format, stated exactly because it is unusual: the Authorization header value is the raw access token with NO scheme — LaunchDarkly's documentation states the value of the Authorization header must be the access token itself, so the stored material is the bare token string and the injector sends it verbatim.\n\nPrefer a service token over a personal token: service tokens are account-level and are not tied to one member's continued employment. Expiry and revocation behavior, LaunchDarkly access tokens do not carry an automatic TTL — a token remains valid until it is reset (rotated) or deleted on the Authorization page, so rotation cadence is the custody job's responsibility and a leaked value must be reset explicitly; resetting or deleting invalidates the value immediately and it fails closed.\n\nNote the gap: changing the role attached to a token narrows its future authorization decisions, and disabling the creating member does not invalidate a service token they created — revocation is per-token. Each token is pinned to an API version at creation; confirm the pinned version serves the registered /api/v2 paths (or send LD-API-Version per request — the pinned-token approach is the default this pack assumes).\n\nLeast privilege: attach a custom role granting only the actions the enabled capabilities need, scoped to the specific projects and environments this pack is bound to — in particular, grant flag-targeting write actions on production environments only where the R3 update capability is intentionally enabled, since the same role gates the deploy-equivalent toggle.\n\nExecutor hygiene: the value must live only in executor memory for the lifetime of a call, must never be written to logs, traces or diagnostics, and must not appear in crash dumps; a deployment that cannot meet that bar must not enable the pack."
  },
  "capabilities": [
    {
      "capability_id": "launchdarkly.projects.read",
      "version": "1.0.0",
      "kind": "tool",
      "risk_tier": "R0",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "internal",
      "egress_allowlist": [
        "launchdarkly-api.invalid"
      ],
      "endpoint": "https://launchdarkly-api.invalid/api/v2/projects",
      "method": "GET",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-launchdarkly-service-token",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "read"
      ],
      "resource_id": "launchdarkly-account",
      "description": "List projects in the LaunchDarkly account — a collection read (paginated per the API version changelog) of project keys, names and environments.\n\nThe host is a reserved placeholder: substitute the customer's LaunchDarkly base URI before enabling.",
      "requires_review": true
    },
    {
      "capability_id": "launchdarkly.flags.read",
      "version": "1.0.0",
      "kind": "tool",
      "risk_tier": "R0",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "internal",
      "egress_allowlist": [
        "launchdarkly-api.invalid"
      ],
      "endpoint": "https://launchdarkly-api.invalid/api/v2/flags/PROJECT_KEY",
      "method": "GET",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-launchdarkly-service-token",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "read"
      ],
      "resource_id": "launchdarkly-account",
      "description": "List the feature flags in one project — a collection read returning summary representations. PROJECT_KEY is a placeholder to bind before enabling; the host is a reserved placeholder to substitute.",
      "requires_review": true
    },
    {
      "capability_id": "launchdarkly.flag.read",
      "version": "1.0.0",
      "kind": "tool",
      "risk_tier": "R0",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "internal",
      "egress_allowlist": [
        "launchdarkly-api.invalid"
      ],
      "endpoint": "https://launchdarkly-api.invalid/api/v2/flags/PROJECT_KEY/FLAG_KEY",
      "method": "GET",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-launchdarkly-service-token",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "read"
      ],
      "resource_id": "launchdarkly-account",
      "description": "Read one feature flag's full configuration: variations plus the per-environment on/off state, individual context targets, targeting rules and rollout. Data handling: the per-environment targets arrays can contain end-user context keys, which a deployment may classify as personal data — this pack registers the read at internal and the deployment must raise the class if its context keys are personal. PROJECT_KEY and FLAG_KEY are placeholders to bind before enabling.",
      "requires_review": true
    },
    {
      "capability_id": "launchdarkly.flag.create",
      "version": "1.0.0",
      "kind": "tool",
      "risk_tier": "R3",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "internal",
      "egress_allowlist": [
        "launchdarkly-api.invalid"
      ],
      "endpoint": "https://launchdarkly-api.invalid/api/v2/flags/PROJECT_KEY",
      "method": "POST",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-launchdarkly-service-token",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "create",
        "deploy"
      ],
      "resource_id": "launchdarkly-account",
      "description": "Create a feature flag (name, key, kind and variations).\n\nRegistered as create and deploy at the minimum R3 tier: creation is not guaranteed inert — according to the reviewed create reference a flag carries default on/off variations, and once the flag exists, application code evaluating it in an environment receives the flag's OFF variation, which can differ from the application's missing-flag fallback value, so creating a flag can change served behavior in production before any toggle or targeting; deploy is one of the designated actions requiring human approval.\n\nRequest limits: the request body sets the flag's variations and initial settings, which this registration does not constrain beyond the operation's schema. PROJECT_KEY is a placeholder to bind before enabling.",
      "requires_review": true
    },
    {
      "capability_id": "launchdarkly.flag.update",
      "version": "1.0.0",
      "kind": "tool",
      "risk_tier": "R3",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "internal",
      "egress_allowlist": [
        "launchdarkly-api.invalid"
      ],
      "endpoint": "https://launchdarkly-api.invalid/api/v2/flags/PROJECT_KEY/FLAG_KEY",
      "method": "PATCH",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-launchdarkly-service-token",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "update",
        "deploy"
      ],
      "resource_id": "launchdarkly-account",
      "description": "Update a feature flag by JSON patch, JSON merge patch, or semantic patch (Content-Type application/json; domain-model=launchdarkly.semanticpatch). Registered as update and deploy at the minimum R3 tier — the deploy-equivalent capability of this pack: semantic patch instructions such as turnFlagOn, turnFlagOff, addTargets, replaceRules and updateFallthroughVariationOrRollout change what production software serves to end users the moment the call succeeds, and toggling a flag in a production environment is a extensive deploy-equivalent write; deploy is one of the designated actions requiring human approval.\n\nOn supported AAES-mediated execution paths, irreversible actions require approval by an authorized person; this does not prevent calls through bypass or observation-only paths.\n\nRequest limits: the request body is an unrestricted patch document that can also perform settings-only edits (name, tags, maintainer) — because the same endpoint and method covers both, a lower tier would not cover all effects, and this is the pack's single registration of the PATCH operation. Provider-side note: if the target environment requires approvals, LaunchDarkly refuses the direct change with a 405 and an approval request is required — the approvals API is deliberately not registered.\n\nPROJECT_KEY and FLAG_KEY are placeholders to bind before enabling.",
      "requires_review": true
    },
    {
      "capability_id": "launchdarkly.flag.delete",
      "version": "1.0.0",
      "kind": "tool",
      "risk_tier": "R3",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "internal",
      "egress_allowlist": [
        "launchdarkly-api.invalid"
      ],
      "endpoint": "https://launchdarkly-api.invalid/api/v2/flags/PROJECT_KEY/FLAG_KEY",
      "method": "DELETE",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-launchdarkly-service-token",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "delete"
      ],
      "resource_id": "launchdarkly-account",
      "description": "Delete a feature flag from the project: the flag, its variations and all per-environment targeting are removed, and any deployed code still referencing the flag key falls back to the fallback value in the code — an irreversible delete with production-visible effect, registered at the minimum R3 tier. PROJECT_KEY and FLAG_KEY are placeholders to bind before enabling.",
      "requires_review": true
    },
    {
      "capability_id": "launchdarkly.project.delete",
      "version": "1.0.0",
      "kind": "tool",
      "risk_tier": "R3",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "internal",
      "egress_allowlist": [
        "launchdarkly-api.invalid"
      ],
      "endpoint": "https://launchdarkly-api.invalid/api/v2/projects/PROJECT_KEY",
      "method": "DELETE",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-launchdarkly-service-token",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "delete"
      ],
      "resource_id": "launchdarkly-account",
      "description": "Delete an entire project: all flags, environments and segments within it are removed — the most extensive delete this pack registers, at the minimum R3 tier. PROJECT_KEY is a placeholder to bind before enabling.",
      "requires_review": true
    }
  ],
  "resources": [
    {
      "resource_id": "launchdarkly-account",
      "kind": "api",
      "locator": "https://launchdarkly-api.invalid/api/v2",
      "data_class": "internal",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN"
    }
  ],
  "review": {
    "state": "library",
    "date": "2026-09-22",
    "sources": [
      "https://launchdarkly.com/docs/api (retrieved 2026-09-21)",
      "https://launchdarkly.com/docs/api/feature-flags (retrieved 2026-09-21)",
      "https://launchdarkly.com/docs/api/feature-flags/patch-feature-flag (retrieved 2026-09-21)",
      "https://launchdarkly.com/docs/api/access-tokens (retrieved 2026-09-21)",
      "https://launchdarkly.com/docs/api/feature-flags/post-feature-flag (retrieved 2026-09-21)",
      "https://launchdarkly.com/docs/api/projects/delete-project (retrieved 2026-09-21)",
      "https://launchdarkly.com/docs/api/projects/get-projects (retrieved 2026-09-21)",
      "https://launchdarkly.com/docs/api/feature-flags/get-feature-flags (retrieved 2026-09-21)",
      "https://launchdarkly.com/docs/api/feature-flags/delete-feature-flag (retrieved 2026-09-21)"
    ],
    "reviewer_id": "aaes-eng"
  }
}
