Platform-agnostic specifications for PostHog SDK capabilities — the canonical contract every SDK must satisfy so behavior stays on par across platforms (Android, iOS, React Native, JavaScript/Web, Flutter, …).
This repo holds specs and archived change history, not proposal-only RFCs or SDK code.
Implementations live in their own repos (posthog-android, posthog-ios, posthog-js, posthog-flutter, …). Each spec here is
the canonical behavior derived from the shipped implementations plus the relevant backend
service, stating the winner wherever SDKs currently diverge.
The acceptance/ directory contains Gherkin feature files for cross-SDK acceptance tests.
acceptance/public/ covers public SDK API behavior, while acceptance/private/ covers
shared internal SDK behavior such as batching, storage, feature flags, sessions, and replay.
Tags on each feature indicate whether scenarios apply to client SDKs, server SDKs, or both.
The server cases in acceptance/public/identify.feature and
acceptance/public/alias.feature call the SDK, flush, and inspect mock-server
traffic using the draft2 harness. They check delivery rather than private queue
state. Migrated server scenarios use @sdk:server for adapter-declared SDK type
selection; the parameterized examples have per-row @case: labels. An ordinary
single-case scenario needs no authored case ID. Unmigrated client and negative
scenarios retain their preconditions and are not selected by the opt-in tags.
The YAML-parity scenarios use the same Gherkin harness but retain their own
capability-driven selection.
| Capability | Spec | Scope | Status |
|---|---|---|---|
| Logs | openspec/specs/logs/spec.md |
product | Canonical |
| Traces | openspec/specs/traces/spec.md |
product | Canonical |
| MCP Analytics | openspec/specs/mcp-analytics/spec.md |
product | Canonical |
| Tracing Headers | openspec/specs/tracing-headers/spec.md |
cross-SDK correlation | Canonical |
| Alias | openspec/specs/alias/spec.md |
public API | Canonical |
| Capture | openspec/specs/capture/spec.md |
public API | Canonical |
| Capture AI | openspec/specs/capture-ai/spec.md |
public API (server) | Canonical |
| Capture Exception | openspec/specs/capture-exception/spec.md |
public API | Canonical |
| Create Person Profile | openspec/specs/create-person-profile/spec.md |
public API | Canonical |
| Debug | openspec/specs/debug/spec.md |
public API | Canonical |
| Exception Steps | openspec/specs/exception-steps/spec.md |
public API | Canonical |
| Flush | openspec/specs/flush/spec.md |
public API | Canonical |
| Get Anonymous ID | openspec/specs/get-anonymous-id/spec.md |
public API | Canonical |
| Get Distinct ID | openspec/specs/get-distinct-id/spec.md |
public API | Canonical |
| Get Feature Flag | openspec/specs/get-feature-flag/spec.md |
public API | Canonical |
| Get Feature Flag Payload | openspec/specs/get-feature-flag-payload/spec.md |
public API | Canonical |
| Get Feature Flag Result | openspec/specs/get-feature-flag-result/spec.md |
public API | Canonical |
| Get Feature Flags | openspec/specs/get-feature-flags/spec.md |
public API | Canonical |
| Get Feature Flags And Payloads | openspec/specs/get-feature-flags-and-payloads/spec.md |
public API | Canonical |
| Evaluate Flags | openspec/specs/evaluate-flags/spec.md |
public API (server) | Canonical |
| Get Session ID | openspec/specs/get-session-id/spec.md |
public API | Canonical |
| Group | openspec/specs/group/spec.md |
public API | Canonical |
| Group Identify | openspec/specs/group-identify/spec.md |
public API | Canonical |
| Identify | openspec/specs/identify/spec.md |
public API | Canonical |
| Is Feature Enabled | openspec/specs/is-feature-enabled/spec.md |
public API | Canonical |
| Is Opt Out | openspec/specs/is-opt-out/spec.md |
public API | Canonical |
| Is Session Replay Active | openspec/specs/is-session-replay-active/spec.md |
public API | Canonical |
| On Feature Flags | openspec/specs/on-feature-flags/spec.md |
public API | Canonical |
| Opt In | openspec/specs/opt-in/spec.md |
public API | Canonical |
| Register | openspec/specs/register/spec.md |
public API | Canonical |
| Reload Feature Flags | openspec/specs/reload-feature-flags/spec.md |
public API | Canonical |
| Reset | openspec/specs/reset/spec.md |
public API | Canonical |
| Reset Group Properties For Flags | openspec/specs/reset-group-properties-for-flags/spec.md |
public API | Canonical |
| Reset Person Properties For Flags | openspec/specs/reset-person-properties-for-flags/spec.md |
public API | Canonical |
| Screen | openspec/specs/screen/spec.md |
public API | Canonical |
| Set Group Properties For Flags | openspec/specs/set-group-properties-for-flags/spec.md |
public API | Canonical |
| Set Person Properties | openspec/specs/set-person-properties/spec.md |
public API | Canonical |
| Set Person Properties For Flags | openspec/specs/set-person-properties-for-flags/spec.md |
public API | Canonical |
| Setup | openspec/specs/setup/spec.md |
public API | Canonical |
| Shutdown | openspec/specs/shutdown/spec.md |
public API | Canonical |
| Start Session Recording | openspec/specs/start-session-recording/spec.md |
public API | Canonical |
| Stop Session Recording | openspec/specs/stop-session-recording/spec.md |
public API | Canonical |
| Unregister | openspec/specs/unregister/spec.md |
public API | Canonical |
| Application Lifecycle | openspec/specs/application-lifecycle/spec.md |
internal behavior | Canonical |
| Autocapture | openspec/specs/autocapture/spec.md |
internal behavior | Canonical |
| Before Send Hook | openspec/specs/before-send-hook/spec.md |
internal behavior | Canonical |
| Consent Gating | openspec/specs/consent-gating/spec.md |
internal behavior | Canonical |
| Device ID Generator | openspec/specs/device-id-generator/spec.md |
internal behavior | Canonical |
| Event Batcher | openspec/specs/event-batcher/spec.md |
internal behavior | Canonical |
| Exception Event Metadata | openspec/specs/exception-event-metadata/spec.md |
internal behavior (client/server) | Canonical |
| Feature Flag Cache | openspec/specs/feature-flag-cache/spec.md |
internal behavior | Canonical |
| Feature Flag Called Tracker | openspec/specs/feature-flag-called-tracker/spec.md |
internal behavior | Canonical |
| Flag Definition Loader | openspec/specs/flag-definition-loader/spec.md |
internal behavior | Canonical |
| HTTP Client | openspec/specs/http-client/spec.md |
internal behavior | Canonical |
| Local Feature Flag Evaluator | openspec/specs/local-feature-flag-evaluator/spec.md |
internal behavior | Canonical |
| Persistent Storage | openspec/specs/persistent-storage/spec.md |
internal behavior | Canonical |
| Remote Config | openspec/specs/remote-config/spec.md |
internal behavior | Canonical |
| Retry Queue | openspec/specs/retry-queue/spec.md |
internal behavior | Canonical |
| Session Manager | openspec/specs/session-manager/spec.md |
internal behavior | Canonical |
| Session Replay Debug Properties | openspec/specs/session-replay-debug-properties/spec.md |
internal behavior | Canonical |
| Session Replay Ingestion Controls | openspec/specs/session-replay-ingestion-controls/spec.md |
internal behavior | Canonical |
| Session Replay Privacy | openspec/specs/session-replay-privacy/spec.md |
internal behavior | Canonical |
| Surveys | openspec/specs/surveys/spec.md |
internal behavior | Canonical |
Each capability is one folder under openspec/specs/<capability>/. A new capability is a new
sibling folder — never folded into an existing spec.
This repo uses OpenSpec for spec-driven development. Install the CLI to propose and validate changes:
npm install -g @fission-ai/openspecThe repo includes shared OpenSpec agent skills for Codex and pi under .agents/skills/.
Claude Code uses the same files through the .claude symlink, while pi-specific prompt
templates remain under .pi/prompts/. The commands below use Claude Code syntax; in pi,
replace : with - (for example, /opsx-propose). All integrations also support standalone
OpenSpec stores when a store is named.
The source of truth is openspec/specs/<capability>/spec.md. You never hand-edit it — you
propose a change, implement it, and archiving syncs the change into the spec.
openspec/
├── config.yaml workflow schema and artifact rules
├── project.md project context + conventions
├── specs/<capability>/spec.md current truth (one folder per capability)
└── changes/ in-flight changes; archive/ holds finished ones
Workflow (OpenSpec CLI + /opsx agent commands):
- Propose —
/opsx:propose add-<capability>(oropenspec new change "<name>"). Createschanges/<name>/withproposal.md,design.md,tasks.md, and a delta spec underchanges/<name>/specs/<capability>/spec.md. - Apply —
/opsx:applyto work throughtasks.md. - Archive —
/opsx:archivesyncs the delta intospecs/<capability>/spec.mdand moves the change tochanges/archive/YYYY-MM-DD-<name>/.
All three steps happen on one branch and in the same PR. Before merging, sync the delta into
openspec/specs/ and archive the change. Do not merge proposal-only PRs or defer applying and
archiving to a follow-up PR.
Archived proposal.md files record change history, not active RFCs. Archiving means the spec
change is complete; SDK implementations live in their own repositories and do not need to be
complete before the spec change is archived. See AGENTS.md for agent instructions.
Two kinds of change:
- New capability →
add-<capability>(e.g.add-feature-flags) creates a new spec folder. - Porting a capability to a new SDK →
add-<capability>-<platform>(e.g.add-logs-android), a delta measured against the existing contract.
### Requirement: Public capture API
The SDK SHALL expose ...
#### Scenario: missing level defaults to info
- **WHEN** the app calls `captureLog({ body: "hello" })` with no level
- **THEN** the record has severityNumber 9 (`INFO`)Every requirement needs at least one scenario. Validate with:
openspec validate --specs --strictConformance matrix (per-SDK parity against each spec) — TODO. Track which SDKs satisfy each requirement and where they currently diverge.