Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ Organization owners should apply these settings after this branch is merged:
attached to the overall `OpenAdapt` project while putting the canonical
engine and Desktop cockpit beside it.
4. The Cloud implementation repository is private and cannot be a public
organization pin. The documentation implementation is Internal and remains
reachable through the public docs link instead of occupying a product pin.
organization pin. The documentation implementation is a public Support
repository and remains reachable through the docs link instead of occupying
a product pin.
5. Apply the archive queue in
[REPOSITORY_LIFECYCLE.md](REPOSITORY_LIFECYCLE.md) only after each repository
has an archive notice and any dirty local work is preserved.
Expand Down
42 changes: 24 additions & 18 deletions REPOSITORY_LIFECYCLE.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# OpenAdapt Repository Lifecycle Registry

Last reviewed: 2026-08-18
Last reviewed: 2026-08-26

This public registry separates the product from experiments and records the
intended lifecycle of organization repositories. It does not authorize moving
Expand All @@ -15,6 +15,7 @@ The machine-readable source is [`repository-lifecycle.yml`](repository-lifecycle
| Status | Meaning |
|--------|---------|
| **Production** | Exact latest release in the signed Production channel with an active, unexpired, non-revoked, independently attested acceptance admission |
| **Support** | Current public dependency or operational tool |
| **Beta** | Active product surface with compatibility intent, but not a blanket production-readiness claim |
| **Experimental** | Active prototype or optional component with no production support promise |
| **Research** | Evidence-generating work, not required by the product runtime |
Expand Down Expand Up @@ -71,30 +72,35 @@ empty for that target. The validator does not fall back to an older release.
Static Production membership is forbidden. Consumers derive current Production
at read time from the signed admission, its expiry, and its revocation state.

## Baseline Lifecycle
## Admission-Gated Targets

The baseline applies when a target does not have a current Production
admission. The admission overlay does not rewrite repository history.
The seven product targets do not have fallback lifecycle labels. A target that
doesn't have a current admission is **not actively admitted**. Expiry,
revocation, release drift, an authority failure, or missing evidence produces
the same state. The validator never restores an older admission or replaces
the state with Beta, Experimental, or Early access.

| Repository | Lifecycle | Role |
The signed ledger currently has no active admissions. These are the derived
states:

| Target | Current state | Role |
|------------|-----------|------|
| `OpenAdapt` | **Beta** | Launcher/meta-package and unified CLI |
| `openadapt-flow` | **Beta** | Canonical compiler and governed runtime |
| `openadapt-desktop` | **Beta** | Desktop cockpit for local recording, qualification, execution, evidence review, and governed repair |
| `openadapt-cloud` | **Beta** | Proprietary control plane for managed browser and customer-controlled execution, attended operations, evidence, usage, and billing |
| `openadapt-capture` | **Experimental** | Optional native recorder |
| `openadapt-agent` | **Beta** | Local MCP and Agent Skills bridge for compiled, governed Flow workflows |
| `openadapt-privacy` | **Experimental** | Optional scrubbing component |
| `openadapt-types` | **Experimental** | Interoperability schemas |
| `openadapt-web` | **Internal** | Marketing website implementation |

## Research, Labs, and Internal Work
| `openadapt` | **Not actively admitted** | `OpenAdapt` launcher/meta-package and unified CLI |
| `flow` | **Not actively admitted** | `openadapt-flow` compiler and governed runtime |
| `cloud` | **Not actively admitted** | Proprietary control plane and hosted execution surface |
| `desktop` | **Not actively admitted** | Desktop recording, qualification, execution, evidence, and repair cockpit |
| `capture` | **Not actively admitted** | Native screen, input, timing, window, and media capture |
| `agent` | **Not actively admitted** | Local MCP and Agent Skills bridge for governed Flow workflows |
| `docs` | **Not actively admitted** | `docs.openadapt.ai` deployment sourced from `openadapt-ops` |

## Other Repository Lifecycles

| Group | Repositories |
|-------|--------------|
| **Support** | `.github`, `openadapt-web`, `openadapt-ops`, `openadapt-wright`, `openadapt-herald`, `openadapt-crier`, `openadapt-consilium`, `openadapt-telemetry`, `openadapt-viewer`, `openadapt-blog` |
| **Experimental** | `openadapt-privacy`, `openadapt-types`, `openadapt-console`, `openadapt-tray` |
| **Research** | `openadapt-ml`, `openadapt-evals`, `openadapt-retrieval`, `openadapt-grounding`, `openadapt-verifier` |
| **Internal** | `openadapt-ops`, `openadapt-wright`, `openadapt-herald`, `openadapt-crier`, `openadapt-consilium`, `openadapt-presenter`, `openadapt-bootstrap`, `openadapt-telemetry`, `openadapt-viewer`, `openadapt-blog`, `openadapt-internal`, `openadapt-yc` |
| **Experimental UI/support** | `openadapt-console`, `openadapt-tray` |
| **Internal** | `openadapt-bootstrap`, `openadapt-internal`, `openadapt-yc`, `openadapt-presenter` |
| **Labs/forks** | `OmniMCP` (`omnimcp` locally), `SoM`, `PydanticPrompt` |
| **Archived historical directions** | `OpenAdapter`, `OpenReflector` |
| **Superseded** | `OpenSanitizer` (successor: `openadapt-privacy`) |
Expand Down
46 changes: 28 additions & 18 deletions profile/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,26 +73,36 @@ before extrapolating either result.

## Product Surfaces

| Surface | Lifecycle | Start here |
The signed admission ledger has no active records. Each product target is
therefore **not actively admitted**. A target shows Production only while its
exact release or deployment has an active, signed, expiring, and revocable
admission.

| Target | Current state | Role |
|---|---|---|
| **Open-source product** | **Beta** | [`OpenAdapt`](https://github.com/OpenAdaptAI/OpenAdapt) installs the unified CLI; [`openadapt-flow`](https://github.com/OpenAdaptAI/openadapt-flow) is the canonical compiler and governed runtime. |
| **Desktop cockpit** | **Beta** | [`openadapt-desktop`](https://github.com/OpenAdaptAI/openadapt-desktop) provides local recording, qualification, execution, evidence review, and governed repair. Native installers are published from its releases page. |
| **Cloud control plane** | **Beta** | [`app.openadapt.ai`](https://app.openadapt.ai/) provides managed browser execution plus workflow, evidence, attended-operation, usage, and billing surfaces for customer-controlled execution. Its implementation repository is private. |
| **Native capture** | **Experimental** | [`openadapt-capture`](https://github.com/OpenAdaptAI/openadapt-capture) is the canonical native screen, input, timing, and window-scoped recording component used by Desktop and Flow. |
| **Agent bridge** | **Beta** | [`openadapt-agent`](https://github.com/OpenAdaptAI/openadapt-agent) exposes compiled Flow workflows as local MCP tools and Agent Skills without becoming a second runtime. |
| **Documentation** | **Beta** | [`docs.openadapt.ai`](https://docs.openadapt.ai) is the canonical journey-led site; [`openadapt-ops`](https://github.com/OpenAdaptAI/openadapt-ops) is its **Internal** publishing source. |
| **Evidence and evaluation** | **Research** | [`openadapt-evals`](https://github.com/OpenAdaptAI/openadapt-evals) contains evaluation infrastructure. Runnable references live in [`openadapt-flow/docs/showcase`](https://github.com/OpenAdaptAI/openadapt-flow/tree/main/docs/showcase), with methods and evidence under [`benchmark`](https://github.com/OpenAdaptAI/openadapt-flow/tree/main/benchmark). |

OpenAdapt is one Beta product across browser, Windows, macOS, Linux, RDP, and
Citrix/VDI. Those execution surfaces share one qualification contract while
retaining environment-specific bindings and evidence. Qualification remains
specific to the workflow, application, environment, identity contract, and
effect verifier rather than being inferred from a platform checkmark.

Runnable is not the same as certified safe. Review identity coverage,
postconditions, system-of-record effects, policy, and the published
| `openadapt` | **Not actively admitted** | [`OpenAdapt`](https://github.com/OpenAdaptAI/OpenAdapt) installs the unified CLI. |
| `flow` | **Not actively admitted** | [`openadapt-flow`](https://github.com/OpenAdaptAI/openadapt-flow) is the canonical compiler and governed runtime. |
| `cloud` | **Not actively admitted** | [`app.openadapt.ai`](https://app.openadapt.ai/) provides the control plane for managed browser and customer-controlled execution. Its implementation repository is private. |
| `desktop` | **Not actively admitted** | [`openadapt-desktop`](https://github.com/OpenAdaptAI/openadapt-desktop) provides local recording, qualification, execution, evidence review, and governed repair. |
| `capture` | **Not actively admitted** | [`openadapt-capture`](https://github.com/OpenAdaptAI/openadapt-capture) records native screen, input, timing, and window-scoped evidence for Desktop and Flow. |
| `agent` | **Not actively admitted** | [`openadapt-agent`](https://github.com/OpenAdaptAI/openadapt-agent) exposes governed Flow workflows as local MCP tools and Agent Skills. |
| `docs` | **Not actively admitted** | [`docs.openadapt.ai`](https://docs.openadapt.ai) is the canonical documentation site. [`openadapt-ops`](https://github.com/OpenAdaptAI/openadapt-ops) is its **Support** publishing source. |

[`openadapt-evals`](https://github.com/OpenAdaptAI/openadapt-evals) is a
Research repository. Runnable references live in
[`openadapt-flow/docs/showcase`](https://github.com/OpenAdaptAI/openadapt-flow/tree/main/docs/showcase),
with methods and evidence under
[`benchmark`](https://github.com/OpenAdaptAI/openadapt-flow/tree/main/benchmark).

These targets form one product across browser, Windows, macOS, Linux, RDP, and
Citrix/VDI. The execution surfaces share one qualification contract and retain
environment-specific bindings and evidence. Qualification stays specific to
the workflow, application, environment, identity contract, and effect verifier.

A runnable workflow can still lack certification. Review its identity coverage,
postconditions, system-of-record effects, policy, and published
[limits](https://github.com/OpenAdaptAI/openadapt-flow/blob/main/docs/LIMITS.md)
for each consequential workflow.
before you use it for consequential work.

## Research and Labs

Expand Down
45 changes: 20 additions & 25 deletions repository-lifecycle.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
schema_version: 2
reviewed_on: 2026-08-18
reviewed_on: 2026-08-26
canonical_product:
launcher: OpenAdapt
engine: openadapt-flow
Expand All @@ -16,24 +16,29 @@ public_metadata:
- openadapt-evals
repository_descriptions:
openadapt-desktop: >-
Beta Desktop cockpit for recording, qualification, local execution,
evidence, and governed repair across OpenAdapt workflows.
Desktop cockpit for recording, qualification, local execution, evidence,
and governed repair across OpenAdapt workflows.
openadapt-capture: >-
Native screen, input, timing, and window-scoped recording for OpenAdapt
Desktop and Flow. Experimental component.
Desktop and Flow.
openadapt-agent: >-
Beta local bridge exposing governed OpenAdapt workflows as MCP tools and
Agent Skills; halts remain halts.
Local bridge exposing governed OpenAdapt workflows as MCP tools and Agent
Skills; halts remain halts.
lifecycle:
production: []
beta:
- OpenAdapt
- openadapt-flow
- openadapt-cloud
- openadapt-desktop
- openadapt-agent
support:
- .github
- openadapt-web
- openadapt-ops
- openadapt-wright
- openadapt-herald
- openadapt-crier
- openadapt-consilium
- openadapt-telemetry
- openadapt-viewer
- openadapt-blog
beta: []
experimental:
- openadapt-capture
- openadapt-privacy
- openadapt-types
- openadapt-console
Expand All @@ -45,19 +50,10 @@ lifecycle:
- openadapt-grounding
- openadapt-verifier
internal:
- openadapt-web
- openadapt-ops
- openadapt-wright
- openadapt-herald
- openadapt-crier
- openadapt-consilium
- openadapt-presenter
- openadapt-bootstrap
- openadapt-telemetry
- openadapt-viewer
- openadapt-blog
- openadapt-internal
- openadapt-yc
- openadapt-presenter
labs:
- OmniMCP
- SoM
Expand All @@ -73,5 +69,4 @@ lifecycle:
- OpenAdapter
public_surfaces:
production: []
beta:
- docs.openadapt.ai
beta: []
46 changes: 40 additions & 6 deletions scripts/check_profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from __future__ import annotations

import json
import re
import sys
from pathlib import Path
Expand Down Expand Up @@ -54,6 +55,7 @@
LIFECYCLE_REPOSITORY_RE = re.compile(r"^ - (\S+)$")
EXPECTED_LIFECYCLE_GROUPS = {
"production",
"support",
"beta",
"experimental",
"research",
Expand All @@ -65,11 +67,10 @@
"archived",
}
EXPECTED_CRITICAL_LIFECYCLES = {
"OpenAdapt": "beta",
"openadapt-flow": "beta",
"openadapt-desktop": "beta",
"openadapt-agent": "beta",
"openadapt-capture": "experimental",
".github": "support",
"openadapt-web": "support",
"openadapt-ops": "support",
"openadapt-blog": "support",
"OpenAdapter": "archived",
"OpenReflector": "archived",
}
Expand Down Expand Up @@ -141,11 +142,44 @@ def main() -> int:
errors.append(f"profile/README.md is missing required links: {missing_links}")

try:
validate_files(ROOT)
active_admissions = validate_files(ROOT)
except LifecycleError as exc:
errors.append(f"Production lifecycle refused: {exc}")
active_admissions = {}

policy = json.loads(
(ROOT / "production-lifecycle-policy.json").read_text(encoding="utf-8")
)
for target in policy["targets"]:
target_id = target["id"]
state = (
"Production"
if target_id in active_admissions
else "Not actively admitted"
)
marker = f"| `{target_id}` | **{state}** |"
for path, text in (
(PROFILE, profile_text),
(LIFECYCLE_DOC, LIFECYCLE_DOC.read_text(encoding="utf-8")),
):
if marker not in text:
errors.append(
f"{path.relative_to(ROOT)} does not match the derived state for "
f"target {target_id}: {state}"
)

lifecycle_text = LIFECYCLE_DATA.read_text(encoding="utf-8")
public_metadata_text = lifecycle_text.split("lifecycle:\n", maxsplit=1)[0]
static_target_labels = sorted(
label
for label in ("Beta", "Experimental", "Early access", "Exploratory")
if re.search(rf"\b{re.escape(label)}\b", public_metadata_text, re.IGNORECASE)
)
if static_target_labels:
errors.append(
"repository-lifecycle.yml public target metadata contains static "
f"lifecycle labels: {static_target_labels}"
)
pinned_section = lifecycle_text.split(" pinned_repositories:\n", maxsplit=1)
if len(pinned_section) != 2:
errors.append("repository-lifecycle.yml is missing pinned_repositories")
Expand Down
6 changes: 3 additions & 3 deletions scripts/validate_production_lifecycle.py
Original file line number Diff line number Diff line change
Expand Up @@ -1627,10 +1627,10 @@ def validate(
for group, subjects in lifecycle.items()
if group != "production" and target["lifecycle_subject"] in subjects
]
if len(memberships) != 1:
if memberships:
raise LifecycleError(
f"target {target_id} must have exactly one baseline lifecycle "
f"membership; got {memberships}"
f"target {target_id} has static lifecycle membership {memberships}; "
"derive its state only from active admissions"
)
return active

Expand Down
39 changes: 39 additions & 0 deletions tests/test_production_lifecycle.py
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,45 @@ def test_registry_membership_without_admission_is_refused(self) -> None:
with self.assertRaisesRegex(lifecycle.LifecycleError, "static Production"):
validate_case(empty_admissions(), repositories=["openadapt-flow"])

def test_static_repository_lifecycle_for_target_is_refused(self) -> None:
repositories, surfaces = lifecycle.load_lifecycle()
repositories = copy.deepcopy(repositories)
repositories["beta"].append("openadapt-flow")
with self.assertRaisesRegex(
lifecycle.LifecycleError, "static lifecycle membership"
):
lifecycle.validate(
load_policy(),
empty_admissions(),
repositories,
surfaces,
policy_sha256=POLICY_DIGEST,
now=NOW,
)

def test_static_public_surface_lifecycle_for_target_is_refused(self) -> None:
repositories, surfaces = lifecycle.load_lifecycle()
surfaces = copy.deepcopy(surfaces)
surfaces["beta"].append("docs.openadapt.ai")
with self.assertRaisesRegex(
lifecycle.LifecycleError, "static lifecycle membership"
):
lifecycle.validate(
load_policy(),
empty_admissions(),
repositories,
surfaces,
policy_sha256=POLICY_DIGEST,
now=NOW,
)

def test_current_public_support_repositories_remain_classified(self) -> None:
repositories, _surfaces = lifecycle.load_lifecycle()
self.assertGreaterEqual(
set(repositories["support"]),
{".github", "openadapt-web", "openadapt-ops", "openadapt-blog"},
)

def test_admission_derives_production_without_static_membership(self) -> None:
admissions, _summary, remote = build_case()
self.assertEqual(
Expand Down