Skip to content

Add OpenFeature (Python) feature flags provider docs#18006

Merged
gustavohstrassburger merged 1 commit into
masterfrom
posthog-code/openfeature-provider-docs
Jul 1, 2026
Merged

Add OpenFeature (Python) feature flags provider docs#18006
gustavohstrassburger merged 1 commit into
masterfrom
posthog-code/openfeature-provider-docs

Conversation

@gustavohstrassburger

Copy link
Copy Markdown
Contributor

What

Adds docs for the official PostHog OpenFeature provider for Python (openfeature-provider-posthog).

This is the companion to PostHog/posthog-python#695, which adds the provider. Per review feedback, the provider's README is kept minimal and points here as the single source of truth (so install/usage snippets don't drift in the package repo).

Changes

  • New page: contents/docs/feature-flags/installation/openfeature.mdx — install, usage/registration with the OpenFeature SDK, evaluation-context → PostHog mapping (targeting_keydistinct_id, groups/group_properties, person properties), supported flag types (boolean/string/number/object), and provider options.
  • Registered it in the feature-flags Installation nav (after Python) in src/navs/index.js.

Notes

  • The package isn't published to PyPI yet — this can merge once openfeature-provider-posthog ships (tracked in the posthog-python PR).

🤖 Generated with Claude Code

Documents the official PostHog OpenFeature provider for Python
(`openfeature-provider-posthog`), which the posthog-python provider README now
points to as the single source of truth.

- New page contents/docs/feature-flags/installation/openfeature.mdx covering
  install, usage/registration, evaluation-context mapping, supported flag types,
  and provider options.
- Register it in the feature-flags Installation nav (after Python).

Generated-By: PostHog Code
Task-Id: 392fb0da-49bb-4c96-96c7-1b39b0348d32
@github-actions

Copy link
Copy Markdown
Contributor

Vale prose linter → found 3 errors, 1 warnings, 0 suggestions in your markdown

Full report → Copy the linter results into an LLM to batch-fix issues.

Linter being weird? Update the rules!

contents/docs/feature-flags/installation/openfeature.mdx — 3 errors, 1 warnings, 0 suggestions
Line Severity Message Rule
11:118 warning Capitalize 'Feature Flags' for PostHog's product. Use 'feature flags' for the general industry concept. PostHogBase.ProductNames
49:38 error Hi, Andy here... use an en dash ( – ) with spaces. On Mac, holding down the Option and hyphen key will give you an en dash. PostHogBase.EnDash
79:25 error Hi, Andy here... use an en dash ( – ) with spaces. On Mac, holding down the Option and hyphen key will give you an en dash. PostHogBase.EnDash
80:30 error Hi, Andy here... use an en dash ( – ) with spaces. On Mac, holding down the Option and hyphen key will give you an en dash. PostHogBase.EnDash

@github-actions

github-actions Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Deploy preview

Status Details Updated (UTC)
🟢 Ready View preview Jun 29, 2026 02:23PM

@github-actions

Copy link
Copy Markdown
Contributor

Bundle report

Total JS (gzip)

6.22 MiB (+0.0 KiB / +0.0%)

Eager graph (static-import closure per entrypoint)

Entrypoint Eager size Budget Modules
app 24.17 MiB (+0.1 KiB / +0.0%) report-only 5515
Largest modules in the app closure
Module Size
css ./node_modules/.pnpm/css-loader@5.2.7_webpack@5.101.3/node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[8].oneOf[1].use[1]!./node_modules/.pnpm/postcss-loader@4.3.0_postcss@8.5.6_webpack@5.101.3/node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[8].oneOf[1].use[2]!./src/styles/global.css 710.3 KiB
./src/components/Stickers/Stickers.tsx 696.4 KiB
./.cache/caches/gatsby-plugin-mdx/mdx-scopes-dir/31a094f140f119e73085d847ae81b99b.js + 2 modules 553.6 KiB
./node_modules/.pnpm/@radix-ui+react-icons@1.3.2_react@18.3.1/node_modules/@radix-ui/react-icons/dist/react-icons.esm.js 481.4 KiB
./node_modules/.pnpm/@codemirror+view@6.38.2/node_modules/@codemirror/view/dist/index.js 458.1 KiB
./node_modules/.pnpm/rehype-raw@7.0.0/node_modules/rehype-raw/lib/index.js + 29 modules 395.1 KiB
./node_modules/.pnpm/@posthog+icons@0.36.6_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.cjs.js 364.8 KiB
./node_modules/.pnpm/@posthog+icons@0.36.6_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js 354.8 KiB
./src/hooks/useCustomers.tsx + 54 modules 353.9 KiB
./node_modules/.pnpm/react-markdown@8.0.7_@types+react@16.14.66_react@18.3.1/node_modules/react-markdown/lib/react-markdown.js + 88 modules 351.4 KiB
./node_modules/.pnpm/cloudinary-core@2.14.0_lodash@4.17.21/node_modules/cloudinary-core/cloudinary-core.js 281.9 KiB
./src/components/ProductComparisonTable/index.tsx + 116 modules 267.6 KiB
./node_modules/.pnpm/@codesandbox+sandpack-react@2.20.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@codesandbox/sandpack-react/dist/index.mjs 266.6 KiB
./node_modules/.pnpm/d3@7.9.0/node_modules/d3/src/index.js + 208 modules 247.4 KiB
./src/components/Pricing/PricingSlider/Slider.tsx + 87 modules 239.9 KiB

Eager-graph budgets are report-only until a baseline is established. Sizes are gzip of public/**/*.js; eager size is webpack module source bytes.

gustavohstrassburger added a commit to PostHog/posthog-python that referenced this pull request Jun 29, 2026
Per review: don't keep a separate provider README that drifts — point to the
PostHog docs (single source of truth) instead. Companion docs page is added in
PostHog/posthog.com#18006.

- Delete openfeature-provider/README.md.
- pyproject: drop the `readme` field (it referenced the deleted file) and add a
  Documentation URL so the PyPI page links straight to the docs.
- Root README: the OpenFeature entry now links to
  https://posthog.com/docs/feature-flags/installation/openfeature instead of the
  in-repo provider README.

uv build + twine check still pass (only a non-fatal missing-long_description
warning, expected without a README).

Generated-By: PostHog Code
Task-Id: 392fb0da-49bb-4c96-96c7-1b39b0348d32
@turnipdabeets turnipdabeets requested review from a team, haacked and marandaneto June 30, 2026 17:33
gustavohstrassburger added a commit to PostHog/posthog-python that referenced this pull request Jun 30, 2026
* Add official PostHog OpenFeature provider

Adds an official PostHog provider for the OpenFeature Python SDK, shipped as a
separate distribution (`openfeature-provider-posthog`) under the OpenFeature
namespace package `openfeature.contrib.provider.posthog`, living in this repo
alongside the SDK.

The provider wraps a configured `posthog.Posthog` client and resolves all five
OpenFeature flag types via the modern, non-deprecated `get_feature_flag_result`
(one call yields value + variant + payload + reason):

- boolean -> `enabled`
- string  -> the multivariate variant key
- int/float -> the variant parsed as a number
- object  -> the flag's JSON payload (full object/JSON support)

Evaluation context maps `targeting_key` -> `distinct_id`, reserved attributes
`groups`/`group_properties` -> PostHog groups, and all other attributes ->
`person_properties`. A missing targeting key raises `TargetingKeyMissingError`
unless `default_distinct_id` is set; type mismatches raise `TypeMismatchError`
so the OpenFeature client returns the caller's default per spec.

Repo wiring:
- New `openfeature-provider` CI job (mirrors the django5 integration job):
  uv sync, pytest, ruff, mypy, build + twine check in the sub-project's own env.
- `mypy.ini`: exclude `openfeature-provider/.*` from the root mypy pass (the
  namespace tree is type-checked in its own env where openfeature-sdk is present).
- README link to the provider.

The new top-level `openfeature/` tree is isolated from the `posthog` build
(explicit packages list) and from the `posthog.*`-scoped public-API snapshot.

Generated-By: PostHog Code
Task-Id: 392fb0da-49bb-4c96-96c7-1b39b0348d32

* Address review: reason mapping, init logging, parametrized tests

- _map_reason: a disabled (enabled=False) result now maps to Reason.DEFAULT
  (the flag is active but no targeting condition matched), reserving
  Reason.DISABLED for when the reason text says the flag itself is off.
  PostHog returns None (-> FlagNotFoundError) for archived/missing flags.
- initialize: log a WARNING (with exc_info) instead of silently swallowing a
  load_feature_flags() failure, so a misconfigured personal_api_key / host /
  permissions is visible while still falling back to remote evaluation.
- tests: collapse the boolean reason-mapping and number-parsing cases into
  @pytest.mark.parametrize, and add coverage for the initialize logging paths.

Generated-By: PostHog Code
Task-Id: 392fb0da-49bb-4c96-96c7-1b39b0348d32

* Address review: add missing tests and optimize _map_reason

* Address review: non-enrollment returns default, _details helper, docs

Addresses review feedback from @haacked and @marandaneto.

- Correctness (haacked + marandaneto): a user who matches no condition or a
  disabled flag (enabled=False, with no variant/object payload) is no longer
  reported as a TYPE_MISMATCH error. The string/integer/float/object resolvers
  now return the caller's default with a normal reason (DEFAULT/DISABLED) in that
  case, and only raise TypeMismatchError for a genuine mismatch (enabled=True but
  the value can't be coerced to the requested type). Applied consistently across
  string, number, and object.
- Refactor (haacked): extract a shared `_details()` helper for the repeated
  reason/flag_metadata wiring across the typed resolvers.
- Tests (haacked): add non-dict `groups`/`group_properties` coercion cases
  asserting they are forwarded as None; add detail tests asserting unmatched
  string/number/object resolution returns the default with no error_code.
- Docs (marandaneto): slim the README to a minimal quickstart and point to
  https://posthog.com/docs/feature-flags as the single source of truth.

Generated-By: PostHog Code
Task-Id: 392fb0da-49bb-4c96-96c7-1b39b0348d32

* Wire openfeature-provider into release + CI, pin posthog

Implements the remaining review suggestions from @marandaneto.

- Release (release.yml): publish `openfeature-provider-posthog` as a second
  distribution. Sampo already auto-discovers the package (it has its own
  pyproject), so the new steps only build/publish/tag the provider when this
  release actually bumped its version (a changeset targeting
  `pypi/openfeature-provider-posthog`). posthog-only releases skip them, and they
  run after the posthog publish/tag/release so they can never block the core
  release. Uses the same PyPI OIDC trusted-publishing action as
  posthog/posthoganalytics (a trusted publisher for the new project must be
  registered before the first provider release).
- Sampo: add openfeature-provider/CHANGELOG.md for Sampo to maintain.
- CI (ci.yml): add a clean-env smoke test that installs the built wheel and
  imports openfeature.contrib.provider.posthog, catching namespace-packaging
  regressions that source-tree tests miss.
- pyproject: pin posthog to the tested major (>=7.0.0,<8.0.0); the local-branch
  build via [tool.uv.sources] was already in place.

Generated-By: PostHog Code
Task-Id: 392fb0da-49bb-4c96-96c7-1b39b0348d32

* Make openfeature-provider a uv workspace member so Sampo manages it

Fixes the release/versioning gap @marandaneto found: `sampo add -p
pypi/openfeature-provider-posthog` failed with "not found in the workspace".
Sampo's PyPI adapter only discovers packages listed in the root pyproject's
[tool.uv.workspace] members (plus the root) — there is no auto-discovery — so the
provider was invisible to Sampo and the release detection never triggered.

- Root pyproject: declare a uv workspace with `members = ["openfeature-provider"]`.
  Sampo now discovers `pypi/openfeature-provider-posthog`, so `sampo add` works and
  `sampo release` bumps openfeature-provider/pyproject.toml from a changeset. The
  root uv.lock change is purely additive (only the member + openfeature-sdk; no
  churn to existing posthog pins), and the main `posthog` build is unaffected
  (explicit packages list).
- Provider pyproject: resolve posthog via `{ workspace = true }` instead of a
  path source; drop the now-redundant standalone uv.lock (the workspace shares the
  root lock).
- CI: the provider job now matrixes Python 3.10–3.14 (matching the main package,
  per @marandaneto/@haacked) and uses workspace-aware commands
  (`--package openfeature-provider-posthog`, `uv build --out-dir dist`).
- release.yml: build the provider with `--package ... --out-dir dist` so its
  artifacts stay isolated from the posthog dist.

Verified locally: root posthog sync + import, provider sync/tests (37)/ruff/mypy/
build/twine/clean-env-import across the workspace, and the django5 integration
project (not a member) still syncs standalone. Sampo itself couldn't be run here
(no cargo), but the config matches exactly what its pip adapter parses.

Generated-By: PostHog Code
Task-Id: 392fb0da-49bb-4c96-96c7-1b39b0348d32

* Release matrix for N packages; docs-only README + provider CONTRIBUTING

Addresses further review from @marandaneto.

- release.yml: restructure into the canonical PostHog multi-package shape (cf.
  posthog-ruby). A single approval-gated `version-bump` job (environment
  "Release") bumps versions, commits, and regenerates references; a separate
  `publish` job with no environment runs a `package` matrix
  (fail-fast, max-parallel 1) over posthog, posthoganalytics, and
  openfeature-provider-posthog. Each entry detects whether its version changed
  in the release commit and only then builds/publishes/tags. Keeping the
  approval on version-bump (not the matrix) preserves a single approval per
  release. NOTE: the no-environment publish job means each package's PyPI
  trusted publisher must point at the `publish` job (not an environment) — a
  one-time PyPI-side config matraneto/maintainers control.
- README: drop the install/quickstart snippets that drift; point to
  https://posthog.com/docs/feature-flags (OpenFeature section) as the single
  source of truth.
- Move the development instructions out of the README into a dedicated
  openfeature-provider/CONTRIBUTING.md with the workspace-aware commands.

Generated-By: PostHog Code
Task-Id: 392fb0da-49bb-4c96-96c7-1b39b0348d32

* Drop provider README; point to docs directly

Per review: don't keep a separate provider README that drifts — point to the
PostHog docs (single source of truth) instead. Companion docs page is added in
PostHog/posthog.com#18006.

- Delete openfeature-provider/README.md.
- pyproject: drop the `readme` field (it referenced the deleted file) and add a
  Documentation URL so the PyPI page links straight to the docs.
- Root README: the OpenFeature entry now links to
  https://posthog.com/docs/feature-flags/installation/openfeature instead of the
  in-repo provider README.

uv build + twine check still pass (only a non-fatal missing-long_description
warning, expected without a README).

Generated-By: PostHog Code
Task-Id: 392fb0da-49bb-4c96-96c7-1b39b0348d32

* Fix pyproject readme ref and root README docs link

Follow-up to dropping the provider README (these were left unstaged in the
prior commit, which deleted the README but not its references):

- openfeature-provider/pyproject.toml: drop the `readme = "README.md"` field
  (it pointed at the now-deleted file and would break the build) and add a
  Documentation URL to [project.urls] so PyPI links straight to the docs.
- README.md: the OpenFeature entry links to
  https://posthog.com/docs/feature-flags/installation/openfeature.

Generated-By: PostHog Code
Task-Id: 392fb0da-49bb-4c96-96c7-1b39b0348d32

* Address review: provider changelog title + robust release notes

Addresses @marandaneto's 2026-06-30 review comments:

- openfeature-provider/CHANGELOG.md: title is now `# openfeature-provider-posthog`
  (was `# Changelog`), so Sampo's `## <version>` sections sit under a
  package-named heading.
- release.yml: make the GitHub release-notes extraction robust (the previous
  awk | sed | tac | sed | tac pipeline was fragile). It now falls back to a
  "See <CHANGELOG>" pointer when the changelog is missing or has no section yet
  (e.g. a package's first release), so a release is never blocked on notes.
  Verified against the provider changelog (no section -> fallback), the root
  posthog changelog (extracts the latest section), and a missing file.

Not changed, with rationale:
- posthog tag prefix kept as `v` (not `posthog-v`): the Sampo config sets
  `short_tags = "posthog"` which intentionally tags the posthog package as
  `v{version}`, matching existing `vX.Y.Z` tags. Switching to `posthog-v` would
  diverge from both.
- Did not move the root CHANGELOG.md to posthog/CHANGELOG.md: Sampo writes a
  package's changelog in its manifest directory, and the posthog package's
  manifest is the repo root, so root CHANGELOG.md *is* the posthog changelog.
  The posthog-ruby layout works because its gem lives in a posthog-ruby/ subdir;
  replicating it here would require relocating the entire posthog package.

Generated-By: PostHog Code
Task-Id: 392fb0da-49bb-4c96-96c7-1b39b0348d32

* Name-prefix the posthog release tag (posthog-v) like other multi-package repos

Per @marandaneto's review and matching posthog-ruby's multi-package convention.

posthog-ruby tags every package with its name prefix once it went multi-package
(`posthog-ruby-v3.15.1`, `posthog-rails-v3.15.0`) and carries no `short_tags` in
its Sampo config. This mirrors that:

- release.yml: posthog package now tags as `posthog-v{version}` (was `v{version}`),
  so all published packages are consistently name-prefixed
  (`posthog-v…`, `openfeature-provider-posthog-v…`). posthoganalytics stays
  untagged (it is a same-version mirror of posthog).
- .sampo/config.toml: drop `short_tags = "posthog"`. Tags are created manually in
  release.yml, so this was inert, but it implied `v{version}` for posthog and was
  inconsistent with the new prefix; removing it aligns Sampo's default tag format
  with the workflow and with posthog-ruby.

Generated-By: PostHog Code
Task-Id: 392fb0da-49bb-4c96-96c7-1b39b0348d32

* Add changeset for openfeature-provider-posthog initial release

Queues the provider's first release. Sets the manifest to 0.0.0 (the
"nothing released yet" state) and adds a minor changeset so Sampo's release
bumps it to 0.1.0 — the intended first published version.

On merge to main this triggers the release workflow, which (per the per-package
detect gate) publishes ONLY openfeature-provider-posthog 0.1.0 and tags it
openfeature-provider-posthog-v0.1.0; posthog/posthoganalytics are untouched
because the root pyproject doesn't change in this release. The provider's PyPI
pending trusted publisher (no environment) is already registered.

Generated-By: PostHog Code
Task-Id: 392fb0da-49bb-4c96-96c7-1b39b0348d32

* Add branch-only TestPyPI dry-run to rehearse the provider publish

Lets you validate the release end-to-end before merging, without touching prod.

Adds a `dry-run-testpypi` job to release.yml gated on
`github.event_name == 'workflow_dispatch' && github.ref != 'refs/heads/main'`.
When the workflow is manually dispatched on a non-main branch, it runs
`sampo release` (version bump only, no commit), builds
openfeature-provider-posthog, and publishes it to TestPyPI via OIDC — exercising
the Sampo workspace bump and the trusted-publisher handshake. It never touches
main, prod PyPI, git tags, or GitHub releases.

Because release.yml already lives on main with workflow_dispatch, dispatching it
against this branch runs the branch's copy (incl. this job) — so no merge is
needed to test. On real push-to-main releases the job is skipped (ref == main),
so the production flow is unaffected.

Requires a TestPyPI trusted publisher for openfeature-provider-posthog
(workflow release.yml, no environment).

Generated-By: PostHog Code
Task-Id: 392fb0da-49bb-4c96-96c7-1b39b0348d32
@gustavohstrassburger gustavohstrassburger moved this to In Progress in Feature Flags Jul 1, 2026
@gustavohstrassburger gustavohstrassburger merged commit 1386296 into master Jul 1, 2026
19 checks passed
@gustavohstrassburger gustavohstrassburger deleted the posthog-code/openfeature-provider-docs branch July 1, 2026 16:22
@github-project-automation github-project-automation Bot moved this from In Progress to Done in Feature Flags Jul 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants