diff --git a/.agents/plugins/marketplace.json b/.agents/plugins/marketplace.json index c5697ba..54c884e 100644 --- a/.agents/plugins/marketplace.json +++ b/.agents/plugins/marketplace.json @@ -15,7 +15,7 @@ "authentication": "ON_INSTALL" }, "category": "Productivity", - "version": "0.2.0" + "version": "0.2.1" } ] } diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index ae3778e..611ba82 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -23,5 +23,7 @@ jobs: run: python3 -B -m unittest discover -s plugins/codex-orchestration/test -p 'test_*.py' - name: Check standalone catalog run: python3 -B plugins/codex-orchestration/test/check_catalog.py + - name: Check documentation + run: python3 -B plugins/codex-orchestration/test/check_docs.py - name: Check whitespace run: git show --format= --check HEAD diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ac1ba2b..51f3513 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,8 @@ # Contributing -This repository maintains one plugin: `plugins/codex-orchestration/`. Keep changes focused on its existing project setup, delegation, documentation and validation responsibilities. The repository is initially private; collaboration requires access. A distribution license must be selected before the planned public release. +This public repository maintains one plugin: `plugins/codex-orchestration/`. Keep changes focused on its existing project setup, delegation, documentation and validation responsibilities. Distribution terms remain under review; see [licensing status](README.md#licensing-status). + +The owner, `Number531`, is currently the only user with repository write/admin access. Community members can report issues and propose changes through pull requests; the owner decides what to accept and merge. A proposed contribution does not grant write access. Repository permissions and the license governing copies are separate. ## Local development @@ -9,12 +11,13 @@ Use Python 3.11+ and Git. No Python packages are needed for the deterministic te ```sh python3 -B -m unittest discover -s plugins/codex-orchestration/test -p 'test_*.py' python3 -B plugins/codex-orchestration/test/check_catalog.py +python3 -B plugins/codex-orchestration/test/check_docs.py git diff --check ``` Read [validation and compatibility](plugins/codex-orchestration/docs/validation.md) before running native or live checks. Do not automatically invoke paid services, change global trust, install the plugin for someone else, or update their real project as part of a test. -GitHub Actions runs the deterministic unit and catalog checks on pushes and pull requests using Python 3.11. Its token has read-only repository access, checkout does not persist credentials, and action dependencies are pinned. Native/live checks remain opt-in; a green CI run does not qualify a desktop client. +GitHub Actions runs the deterministic unit, catalog and documentation checks on pushes and pull requests using Python 3.11. The offline documentation check covers tracked Markdown inline local links, ATX heading anchors, and JSON/TOML fenced examples; external URLs and shell commands require separate review. Its token has read-only repository access, checkout does not persist credentials, and action dependencies are pinned. Native/live checks remain opt-in; a green CI run does not qualify a desktop client. ## Changes and pull requests @@ -28,13 +31,15 @@ Avoid adding a workflow framework, automatic updater, account-wide control claim ## Report a problem -Use an issue in this repository for a non-sensitive bug or documentation problem. Include OS, package/client versions, the failing command, expected/observed behavior and a minimal sanitized reproduction. Do not attach full user configuration, prompts or logs containing secrets. Security-sensitive details belong in a private report. +Use [GitHub Issues](https://github.com/Number531/Codex-Orchestration/issues) for a non-sensitive bug, feature request or documentation problem. Sign in to GitHub to submit an issue; no repository invitation is required. Include OS, package/client versions, the failing command, expected/observed behavior and a minimal sanitized reproduction. Do not attach full user configuration, prompts or logs containing secrets. Security-sensitive details belong in the [private reporting channel](SECURITY.md#report-a-vulnerability). ## Release preparation -Before a public launch: +Follow the [versioned release and rollback procedure](docs/releasing.md). Changes to `main` require a pull request, the passing `contracts` check and resolved review conversations. Force-pushes and branch deletion are blocked. Zero required GitHub approvals accommodates a solo maintainer; retain an independent review before merging. + +Before a versioned release: -1. Confirm the intended license and ownership/branding permissions, add the selected license, and align manifest metadata and documentation. No license is selected by this initial extraction. +1. Confirm the intended license and ownership/branding permissions, add the selected license, and align manifest metadata and documentation. Public repository visibility does not settle these terms. 2. Review the complete candidate tree and reachable history for credentials, customer data, internal material and third-party content. This repository starts from selected package files rather than importing the original repository's history. 3. Pass deterministic checks, review the final diff independently, and record native/client validation honestly. Resolve or explicitly disclose compatibility assumptions. 4. Trial the documented install, setup, trust, toggle, update and removal procedures in a disposable project with a separate authorized account. Confirm that the configured models are available there. diff --git a/README.md b/README.md index 989912b..1a87350 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Cost-aware delegation for Codex, with named specialist agents and an optional mo An orchestrating agent can choose tasks dynamically while delegating through registered roles with fixed model and reasoning settings. The optional guard rejects covered spawn requests that violate the project policy. **Enforcement starts off.** -This repository is initially private. GitHub read access is required until the owner changes its visibility. It is a repository-hosted Codex catalog, not a public directory listing or an OpenAI endorsement. No license has been selected for public distribution yet. +This repository is public and accepts community issue reports. It is a repository-hosted Codex catalog; an OpenAI public-directory listing and endorsement have not been granted. Distribution terms remain under review; see [licensing status](#licensing-status). ## Start here @@ -16,6 +16,7 @@ This repository is initially private. GitHub read access is required until the o | Understand what has actually been tested | [Validation and compatibility](plugins/codex-orchestration/docs/validation.md) | | Contribute a change | [Contributing](CONTRIBUTING.md) | | Report a security concern | [Security](SECURITY.md) | +| Report a bug or request an improvement | [GitHub Issues](https://github.com/Number531/Codex-Orchestration/issues) | ## Install the plugin @@ -27,7 +28,7 @@ codex plugin list --available --json --marketplace codex-orchestration codex plugin add codex-orchestration@codex-orchestration ``` -For a private repository, use Git credentials with read access. SSH is also supported: +The HTTPS catalog is publicly readable and requires no repository invitation. SSH is also supported for users with GitHub SSH authentication: ```sh codex plugin marketplace add git@github.com:Number531/Codex-Orchestration.git @@ -45,7 +46,11 @@ Choose one catalog source. If that catalog is already registered, inspect `codex | Package directory | `plugins/codex-orchestration/` | | Native catalog | `.agents/plugins/marketplace.json` | -Version `0.2.0` aligns the plugin, skills and project markers with this repository's community branding. Existing `0.1.0` installations need the [manual migration steps](plugins/codex-orchestration/docs/operations.md#migrate-from-010). The generic role names, model pins and default-off behavior are unchanged. This repository contains no sibling plugins from the original multi-plugin repository. +Version `0.2.0` aligned the plugin, skills and project markers with this repository's community branding. Existing `0.1.0` installations need the [manual migration steps](plugins/codex-orchestration/docs/operations.md#migrate-from-010). The generic role names, model pins and default-off behavior are unchanged. This repository contains no sibling plugins from the original multi-plugin repository. + +## Reviewed versions + +For a reproducible install, add `--ref ` to the marketplace-add command above. Replace the placeholder with a reviewed commit SHA or a published tag from [Releases](https://github.com/Number531/Codex-Orchestration/releases); use one catalog source. No tagged release has been published yet. Review the [upgrade and rollback procedure](plugins/codex-orchestration/docs/operations.md#upgrade-a-project) before changing an existing installation. Maintainers use the [release procedure](docs/releasing.md). ## Development checks @@ -54,10 +59,13 @@ From the repository root, with Python 3.11+ and Git: ```sh python3 -B -m unittest discover -s plugins/codex-orchestration/test -p 'test_*.py' python3 -B plugins/codex-orchestration/test/check_catalog.py +python3 -B plugins/codex-orchestration/test/check_docs.py ``` These checks use synthetic local fixtures and run in [GitHub Actions](.github/workflows/validate.yml). CI does not run paid models or native Codex sessions. Native engine checks, Desktop installation/trust, and live model access are separate validation surfaces; see the [compatibility guide](plugins/codex-orchestration/docs/validation.md). -## Before a public release +## Licensing status + +A distribution license reflecting the owner's intended free-use and enterprise restrictions is still being selected. No project license has been adopted. Public visibility does not itself grant general reuse or redistribution rights; GitHub explains the [default licensing position and platform fork rights](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/licensing-a-repository). -Choose a license and update the package metadata, confirm branding and source ownership, test onboarding with a separate account, and review the repository contents and history before changing visibility. Publishing to GitHub and submitting to OpenAI's public plugin directory are separate decisions. See [maintainer release guidance](CONTRIBUTING.md#release-preparation). +Before a versioned release, finalize the license and package metadata, confirm source ownership, and record supported-client validation. Desktop UI and live-account qualification remain open. See [maintainer release guidance](CONTRIBUTING.md#release-preparation). Publishing a GitHub release and submitting to OpenAI's public plugin directory are separate decisions. diff --git a/SECURITY.md b/SECURITY.md index e455326..43beed8 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -10,6 +10,8 @@ The shipped installer and guard make no network calls and load no credentials. C ## Report a vulnerability -Use GitHub's private vulnerability reporting for this repository if that option is enabled. While the repository is private, an authorized collaborator can contact the owner through their established private channel. If no private reporting channel is available, open only a minimal, non-sensitive issue requesting one; do not include exploit details, credentials or customer data. +As of 2026-09-13, this repository is public and GitHub private vulnerability reporting, secret scanning and repository push protection are enabled and verified through GitHub's API. These controls do not guarantee that every secret or vulnerability will be detected. Maintainers should recheck the settings before releases; see the [release procedure](docs/releasing.md#repository-security-settings). + +Use [Report a vulnerability](https://github.com/Number531/Codex-Orchestration/security/advisories/new) for security-sensitive findings. Sign in to GitHub and use the private advisory form. If that channel is unavailable, open only a minimal, non-sensitive issue requesting a private contact route; do not include exploit details, credentials or customer data. Provide the affected package/client versions, a sanitized reproduction, the violated boundary and observed impact through the private channel. Do not publish a working exploit or sensitive logs in a public issue. This initial project makes no response-time or long-term support commitment. diff --git a/docs/releasing.md b/docs/releasing.md new file mode 100644 index 0000000..bfc690f --- /dev/null +++ b/docs/releasing.md @@ -0,0 +1,39 @@ +# Releasing Codex-Orchestration + +Release only a reviewed commit of this single plugin. A tag selects a repository snapshot; the plugin version, both manifests, catalog entry and changelog must agree on the release version. + +## Prepare and validate + +1. Confirm the license, attribution and intended distribution audience. Review the candidate tree and reachable history for sensitive material; a pattern scan does not establish ownership or prove that every secret is absent. +2. Update both package manifests, the catalog version, changelog and affected onboarding/compatibility documentation. Keep delegation enforcement off by default. +3. Run the deterministic checks from the repository root: + +```sh +python3 -B -m unittest discover -s plugins/codex-orchestration/test -p 'test_*.py' +python3 -B plugins/codex-orchestration/test/check_catalog.py +python3 -B plugins/codex-orchestration/test/check_docs.py +git diff --check +``` + +4. Trial discovery, installation, project setup and default-off status in an isolated configuration/cache and disposable Git project. Confirm that the installed cache matches the reviewed package. Record exact client/OS versions and distinguish CLI, Desktop engine and Desktop UI results. Native and live checks remain opt-in; keep credentials and session records out of release artifacts. +5. Obtain independent review, open a pull request and require passing CI before merging. Confirm the merged tree is the reviewed tree. Keep main protected and do not bypass failing required checks. + +## Publish a reviewed version + +After the owner authorizes publication, create a version tag such as `vX.Y.Z` at the exact validated merge commit and publish a GitHub release using that tag. Replace placeholders with the reviewed version and commit. Do not move or force-update a published tag; ship a new version for corrections. + +The release notes should state the change, migration requirements, tested client/OS versions, known limitations, license and default-off behavior. Verify the release and tag resolve to the intended commit, then trial catalog discovery from that tag. GitHub's generated source archives are sufficient for this package; no custom binary build pipeline is required. + +Users can add `--ref ` to the documented marketplace-add command to select a reviewed version. A pinned catalog remains on that ref when refreshed; moving to another release requires reviewing and updating the catalog source/ref through the client's supported marketplace flow. Plugin-cache updates and project-asset updates are separate. + +## Repository security settings + +Maintain pull-request-only changes to main, the required `contracts` check from GitHub Actions, resolved review conversations, and blocked force-pushes/deletions. A solo maintainer may use zero required approvals while retaining independent review in the contribution process; require an additional reviewer when one is available. + +This repository is public. GitHub private vulnerability reporting, secret scanning and repository push protection were enabled and verified on 2026-09-13. Before a release, recheck those settings and the private reporting link in [SECURITY.md](../SECURITY.md#report-a-vulnerability). Do not infer current settings from this dated record or enroll in a paid product unintentionally. + +Changing repository visibility, publishing a release and submitting to OpenAI's public plugin directory are separate owner-authorized actions. A repository catalog is not an OpenAI directory listing. + +## Roll back an adoption + +Review the [project upgrade and recovery guide](../plugins/codex-orchestration/docs/operations.md#upgrade-a-project). Select the prior reviewed package version for the plugin cache and separately reconcile its project files, preserving custom roles, policy and toggle values. Disabling the plugin does not remove project assets. If reverting enforcement, explicitly set the project's guard off before removing its script/hook. Never use blanket cleanup or history rewriting to discard unrelated work. diff --git a/plugins/codex-orchestration/.codex-plugin/plugin.json b/plugins/codex-orchestration/.codex-plugin/plugin.json index 6c334dd..a64b346 100644 --- a/plugins/codex-orchestration/.codex-plugin/plugin.json +++ b/plugins/codex-orchestration/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "codex-orchestration", - "version": "0.2.0", + "version": "0.2.1", "description": "Team delegation, focused delivery and explicit Codex project setup with an optional model guard.", "author": { "name": "Codex-Orchestration contributors" diff --git a/plugins/codex-orchestration/CHANGELOG.md b/plugins/codex-orchestration/CHANGELOG.md index 5f62c65..9c03854 100644 --- a/plugins/codex-orchestration/CHANGELOG.md +++ b/plugins/codex-orchestration/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 0.2.1 — Unreleased + +Separated installed-plugin and checkout setup instructions, documented project and hook trust separately, and stated the Unix prerequisite and default-off activation guidance. Added offline documentation checks and maintainer release/rollback instructions. The installer, hook, role profiles, model pins and project guidance are unchanged. + +Disposable local-catalog and pinned GitHub-commit installation passed on CLI `0.154.0` and Desktop engine `0.154.0-alpha.6.2` on macOS: three cached skills, matching package files, repeatable setup and guard off. Desktop UI trust and live model access remain unqualified. + +The repository became public on 2026-09-13 with Issues available, private vulnerability reporting enabled, and secret scanning/push protection verified. Updated public access, owner-controlled contribution and security-reporting guidance. Distribution license and tagged release remain pending; public visibility does not grant a project license. + ## 0.2.0 — 2026-09-12 Renamed the plugin/package to `codex-orchestration` and its skills to `orchestration-setup`, `orchestration-delivery` and `orchestration-review`. Updated neutral author/display metadata, project guidance, installer markers, documentation, CI paths and catalog contracts. Global configuration and other repositories are outside this change. diff --git a/plugins/codex-orchestration/README.md b/plugins/codex-orchestration/README.md index bc65bb8..d941359 100644 --- a/plugins/codex-orchestration/README.md +++ b/plugins/codex-orchestration/README.md @@ -1,6 +1,6 @@ # Codex-Orchestration -**Version 0.2.0 · Plugin ID `codex-orchestration` · Guard off by default** +**Version 0.2.1 · Plugin ID `codex-orchestration` · Guard off by default** A small Codex plugin for delegating dynamic tasks through named, model-pinned specialists. It provides three skills, six agent profiles, project guidance, a preview-first installer, and an optional synchronous spawn guard. @@ -8,7 +8,7 @@ For example, a parent can assign repository discovery to `explorer`, implementat ## Requirements -- Python 3.11+ and Git on the machine where project setup and hooks run. Runtime scripts use the standard library; no Python dependency installation is required. +- Python 3.11+ and Git in a Unix environment with `fcntl` and a compatible shell. macOS is the qualified platform. Native Windows Python cannot run this installer; Linux and WSL require their own client validation. Runtime scripts use the standard library; no Python dependency installation is required. - An existing Git project and permission to review and change its project configuration. - A compatible Codex client supporting multi-agent V2, the `fork_turns` spawn field, named profiles and synchronous `PreToolUse` denial. The tested engines were CLI `0.154.0` and Desktop bundled engine `0.154.0-alpha.6.2` on macOS. Other versions require validation. - Access to the configured models through the account/provider used by that client. The bundled Luna/Terra/Sol pins do not grant model access or guarantee prices. Check the [role table and customization guide](docs/configuration.md#bundled-roles) before setup. @@ -17,7 +17,7 @@ The `fork_turns` field and the `collaborationspawn_agent` hook name are compatib ## Install the skills -The standalone repository is [Number531/Codex-Orchestration](https://github.com/Number531/Codex-Orchestration), initially private. Its catalog is `.agents/plugins/marketplace.json`; the marketplace name is `codex-orchestration`. +The standalone repository is [Number531/Codex-Orchestration](https://github.com/Number531/Codex-Orchestration), publicly readable. Its catalog is `.agents/plugins/marketplace.json`; the marketplace name is `codex-orchestration`. ```sh codex plugin marketplace add https://github.com/Number531/Codex-Orchestration.git @@ -25,31 +25,53 @@ codex plugin list --available --json --marketplace codex-orchestration codex plugin add codex-orchestration@codex-orchestration ``` -Private access requires your GitHub credentials. Use the SSH equivalent if that is how you authenticate. In a new Codex session, select the installed `orchestration-setup` skill for your target project. Installation alone does **not** register project agents, trust hooks, or enable the guard. +No repository invitation is required for HTTPS access. Use the SSH equivalent if that is how you authenticate. Plugin installation makes the skills available; project setup is a separate step. Review the repository's [licensing status](../../README.md#licensing-status) before adoption. -Alternatively, clone a reviewed checkout and use its setup script directly. This installs the project assets without registering plugin skills: +## Set up one project + +Choose one of the following routes. Both target one existing Git worktree and leave the delegation guard off. + +### Installed-plugin route + +1. Open your target Git project in a new Codex session after installing the plugin. +2. Select `orchestration-setup` from the skill picker and ask: “Preview Codex Orchestration setup for this project. Leave enforcement off.” The skill locates its own installed package; no shell variable or second clone is needed. +3. Review the planned files and any conflicts. If the preview is correct, ask the skill to apply it to that project. Do not force an overwrite. +4. Continue with [review and trust](#review-and-trust). + +### Checkout route + +Use this route when you want project configuration without registering the plugin skills. Clone a reviewed checkout, then replace `/absolute/path/to/project` with the existing Git worktree root you want to configure: ```sh git clone https://github.com/Number531/Codex-Orchestration.git cd Codex-Orchestration ORCHESTRATION_PACKAGE="$PWD/plugins/codex-orchestration" +ORCHESTRATION_PROJECT="/absolute/path/to/project" +python3 "$ORCHESTRATION_PACKAGE/scripts/setup.py" --project "$ORCHESTRATION_PROJECT" ``` -## Set up one project - -Use the absolute root of the target Git worktree, not a subdirectory. A separate disposable Git project is a useful first trial. +The default is a read-only preview. It prints the planned paths or `Preview: no changes.` Review the source assets and existing project configuration before applying. In the same shell: ```sh -python3 "$ORCHESTRATION_PACKAGE/scripts/setup.py" --project /absolute/path/to/project +python3 "$ORCHESTRATION_PACKAGE/scripts/setup.py" --project "$ORCHESTRATION_PROJECT" --apply ``` -The default is a read-only preview. It prints the planned paths or `Preview: no changes.` Review the source assets and the target project's existing configuration before applying the plan: +A separate disposable Git project is a useful first trial; the [validation guide](docs/validation.md#try-the-documented-setup-safely) gives complete commands. + +### Review and trust + +Review the resulting project diff before using the installed configuration. Two separate trust decisions matter: + +1. Open Codex in the target project and complete its project-trust prompt after reviewing the project. Project `.codex` settings and hooks load only from a trusted project. +2. In the CLI, open `/hooks`, locate the project hook from `.codex/hooks.json`, and review its command and current definition before trusting it. New or changed non-managed hooks require review again. This trust decision does not turn on delegation enforcement. + +Start a fresh session after profile/config changes. Check the flag from the configured project: ```sh -python3 "$ORCHESTRATION_PACKAGE/scripts/setup.py" --project /absolute/path/to/project --apply +python3 /absolute/path/to/project/.agents/system/hooks/delegation_guard.py --status ``` -Review the resulting project diff, complete the client's normal project/hook trust flow, and start a fresh session. Setup does not grant that trust. If you installed through the plugin manager, `orchestration-setup` resolves its package location; the shell variable above is only for the checkout route. +A new setup should print `Delegation guard: off`. OpenAI documents the [hook review flow](https://learn.chatgpt.com/docs/hooks); Desktop UI qualification is recorded separately in the [compatibility guide](docs/validation.md). Setup never grants trust automatically. New installations leave the guard off. Reruns preserve valid existing flag and model-policy values. A setup conflict stops the operation; use [operations and recovery](docs/operations.md) rather than forcing an overwrite. @@ -57,11 +79,18 @@ Upgrading from `0.1.0` changes the plugin/skill identifiers and managed guidance ## Turn enforcement on or off -In the configured project, after reviewing and authorizing the policy: +Leave enforcement off during ordinary onboarding. Enable it only when a demonstrated delegation-policy issue calls for enforcement and the user authorizes the policy. Turning it on does not fix installation, interpreter, or trust errors. + +To enable enforcement in the configured project: ```sh python3 /absolute/path/to/project/.agents/system/hooks/delegation_guard.py --on python3 /absolute/path/to/project/.agents/system/hooks/delegation_guard.py --status +``` + +To disable it: + +```sh python3 /absolute/path/to/project/.agents/system/hooks/delegation_guard.py --off ``` @@ -84,4 +113,4 @@ These skills do not authorize spending, remote writes, merges, or policy changes - [Validation and compatibility](docs/validation.md): reproducible checks, evidence and unverified surfaces. - [Changelog](CHANGELOG.md), [contribution guidance](../../CONTRIBUTING.md), and [security policy](../../SECURITY.md). -The package has no declared distribution license yet. Keeping the repository private does not settle the licensing decision for a future public release. +The repository is public, but a distribution license has not yet been adopted. See [licensing status](../../README.md#licensing-status) for the current position. diff --git a/plugins/codex-orchestration/docs/validation.md b/plugins/codex-orchestration/docs/validation.md index 4aea639..bf2676b 100644 --- a/plugins/codex-orchestration/docs/validation.md +++ b/plugins/codex-orchestration/docs/validation.md @@ -6,14 +6,21 @@ | Surface | Evidence | Limit | |---|---|---| -| Setup, guard, profiles and package contracts | 50 deterministic unit tests passed for `0.2.0`, including legacy migration refusal and installer lock exclusion. | Synthetic projects do not establish live account access or UI behavior. | +| Setup, guard, profiles, package and documentation contracts | 54 deterministic unit tests passed for the `0.2.1` candidate, including legacy migration refusal, installer lock exclusion and documentation-check regressions. | Synthetic projects do not establish live account access or UI behavior. | | Native spawn behavior | 17 cases passed on CLI `0.154.0` and Desktop engine `0.154.0-alpha.6.2` on macOS, recorded 2026-09-12. | The harness supplies reviewed configuration/trust overrides and a loopback scripted provider. | -| Catalog discovery | Both original tested binaries discovered the original entry without installation. | Standalone catalog identity and consistency are checked separately. | +| Local-catalog installation and setup | CLI `0.154.0` and Desktop engine `0.154.0-alpha.6.2` installed the `0.2.1` candidate on macOS, recorded 2026-09-12. | This is a local-catalog trial; it does not establish GitHub authentication or Desktop UI behavior. | +| Pinned GitHub-commit installation | Both engines installed commit `1ea514efdacb8aa1077e4eb81a8f7d90d1255306` through the GitHub catalog on 2026-09-13. | Used the maintainer's existing Git authentication while the repository was private; no separate community-account trial. | | Desktop UI install/trust and live models | Not established by those tests. | Requires a separately authorized onboarding trial. | | Windows, other clients or versions | Not qualified by the original native matrix. | The installer uses POSIX `fcntl`; the hook command assumes a compatible shell. | The `0.2.0` branding update preserves the guard, six role profiles, model pins and default-off flag. It renames package/skill identifiers and installer markers, and adds refusal checks for recognized legacy guidance/locks. Local setup tests cover that transition. Do not treat inherited native evidence as a newly executed matrix or a test of the renamed plugin's UI installation. +The `0.2.1` trial used a separate temporary Codex configuration/cache and Git project for each executable. Fresh processes listed the installed, enabled plugin; its three skill files and all 30 package files matched the candidate checkout. Setup ran from the installed cache, a second preview reported no changes, and the flag reported off. No auth files were copied, trust granted or live models called. The real global configuration and plugin-registry hashes were unchanged. Codex still discovered the ambient personal marketplace; the test selected only this package and is not a claim of complete operating-system isolation. + +The subsequent pinned GitHub-commit trial repeated those checks successfully on both engines against the exact commit above. Later public-state documentation edits did not change runtime assets. After the visibility change, unauthenticated HTTP requests separately confirmed public repository and Issues access. That access check did not invoke Codex or establish model availability. + +The production Desktop app was not launched for the trial. A safe, documented separate UI profile was not established for that build; qualifying its graphical installation and normal trust flow requires a disposable OS user/VM or a supported isolated app environment. + ## Local checks From the repository root, with Python 3.11+ and Git: @@ -21,9 +28,10 @@ From the repository root, with Python 3.11+ and Git: ```sh python3 -B -m unittest discover -s plugins/codex-orchestration/test -p 'test_*.py' python3 -B plugins/codex-orchestration/test/check_catalog.py +python3 -B plugins/codex-orchestration/test/check_docs.py ``` -Tests cover setup preservation/conflicts, filesystem failures, rollback behavior, guard acceptance/denial, role pins, manifests and synthetic catalogs. The catalog check verifies this repository's single-plugin catalog. They do not install into real projects or global Codex configuration. +Tests cover setup preservation/conflicts, filesystem failures, rollback behavior, guard acceptance/denial, role pins, manifests, synthetic catalogs and documentation-check failures. The catalog check verifies this repository's single-plugin catalog. The offline documentation check validates tracked Markdown inline local links, ATX heading anchors and JSON/TOML fences; it does not execute shell examples or check external URLs. They do not install into real projects or global Codex configuration. ## Try the documented setup safely diff --git a/plugins/codex-orchestration/plugin.json b/plugins/codex-orchestration/plugin.json index e0b0971..a9c7561 100644 --- a/plugins/codex-orchestration/plugin.json +++ b/plugins/codex-orchestration/plugin.json @@ -1,7 +1,7 @@ { "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json", "name": "codex-orchestration", - "version": "0.2.0", + "version": "0.2.1", "description": "Team delegation, focused delivery and explicit Codex project setup with an optional model guard.", "author": { "name": "Codex-Orchestration contributors" diff --git a/plugins/codex-orchestration/test/check_docs.py b/plugins/codex-orchestration/test/check_docs.py new file mode 100644 index 0000000..2c98fd9 --- /dev/null +++ b/plugins/codex-orchestration/test/check_docs.py @@ -0,0 +1,172 @@ +"""Check the repository's tracked Markdown documentation without network access. + +Supported Markdown is deliberately small: ATX headings, inline ``[label](target)`` +links, and fenced JSON or TOML examples. Reference links, HTML anchors, and link +targets with nested parentheses are outside this checker's scope. +""" +from __future__ import annotations + +import json +from pathlib import Path +import re +import subprocess +import sys +import tomllib +from urllib.parse import unquote + + +FENCE_OPEN = re.compile(r"^ {0,3}(?P`{3,}|~{3,})(?P.*)$") +HEADING = re.compile(r"^ {0,3}#{1,6}[ \t]+(?P.*?)[ \t]*#*[ \t]*$") +INLINE_LINK = re.compile(r"\[[^\]\n]*\]\((?P[^()\n]+)\)") +EXTERNAL_TARGET = re.compile(r"^(?:[a-z][a-z0-9+.-]*:|//)", re.IGNORECASE) + + +class DocumentationError(ValueError): + """A local documentation reference or data example is invalid.""" + + +def repository_root() -> Path: + return Path(__file__).resolve().parents[3] + + +def tracked_markdown(root: Path) -> list[Path]: + result = subprocess.run( + ["git", "-C", str(root), "ls-files", "-z", "--", "*.md"], + check=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + files = [root / Path(name.decode("utf-8", "surrogateescape")) + for name in result.stdout.split(b"\0") if name] + for file in files: + if not file.is_file(): + raise DocumentationError(f"{file.relative_to(root)}: tracked Markdown file is unreadable") + return files + + +def closes_fence(line: str, marker: str) -> bool: + character = re.escape(marker[0]) + return bool(re.match(rf"^ {{0,3}}{character}{{{len(marker)},}}[ \t]*$", line)) + + +def heading_slugs(file: Path) -> set[str]: + slugs: set[str] = set() + marker: str | None = None + for line in file.read_text(encoding="utf-8").splitlines(): + if marker: + if closes_fence(line, marker): + marker = None + continue + fence = FENCE_OPEN.match(line) + if fence: + marker = fence["marker"] + continue + heading = HEADING.match(line) + if heading: + slugs.add(slug(heading["text"])) + return slugs + + +def slug(text: str) -> str: + return re.sub(r"[^\w\- ]", "", text.lower()).replace(" ", "-") + + +def local_target(source: Path, target: str, root: Path, line: int) -> tuple[Path, str | None] | None: + target = target.strip() + if target.startswith("<") and target.endswith(">"): + target = target[1:-1] + if EXTERNAL_TARGET.match(target): + return None + + path, separator, fragment = target.partition("#") + destination = source if not path else (source.parent / unquote(path)).resolve() + try: + destination.relative_to(root) + except ValueError as error: + raise DocumentationError( + f"{source.relative_to(root)}:{line}: local link leaves the repository: {target}" + ) from error + if not destination.exists(): + raise DocumentationError(f"{source.relative_to(root)}:{line}: missing local link target: {target}") + return destination, unquote(fragment).lower() if separator else None + + +def validate_example(file: Path, language: str, content: str, start_line: int, root: Path) -> None: + try: + if language == "json": + json.loads(content) + else: + tomllib.loads(content) + except (json.JSONDecodeError, tomllib.TOMLDecodeError) as error: + line = start_line + getattr(error, "lineno", 1) - 1 + raise DocumentationError( + f"{file.relative_to(root)}:{line}: invalid {language} fenced example: {error}" + ) from error + + +def check(root: Path | None = None) -> tuple[int, int]: + """Validate tracked Markdown and return checked local-link and data-block counts.""" + root = (root or repository_root()).resolve() + files = tracked_markdown(root) + anchors = {file.resolve(): heading_slugs(file) for file in files} + links = blocks = 0 + + for file in files: + marker: str | None = None + language = "" + example: list[str] = [] + example_start = 0 + for line_number, line in enumerate(file.read_text(encoding="utf-8").splitlines(), start=1): + if marker: + if closes_fence(line, marker): + if language: + validate_example(file, language, "\n".join(example), example_start, root) + blocks += 1 + marker = None + language = "" + example = [] + elif language: + example.append(line) + continue + + fence = FENCE_OPEN.match(line) + if fence: + marker = fence["marker"] + info = fence["info"].strip().split(maxsplit=1) + language = info[0].lower() if info and info[0].lower() in {"json", "toml"} else "" + example_start = line_number + 1 + continue + + for match in INLINE_LINK.finditer(line): + resolved = local_target(file, match["target"], root, line_number) + if resolved is None: + continue + destination, fragment = resolved + if fragment: + destination_anchors = anchors.get(destination, heading_slugs(destination)) + if fragment not in destination_anchors: + raise DocumentationError( + f"{file.relative_to(root)}:{line_number}: missing local anchor in {match['target']}" + ) + links += 1 + + if marker and language: + raise DocumentationError( + f"{file.relative_to(root)}:{example_start}: unclosed {language} fenced example" + ) + + return links, blocks + + +def main() -> int: + try: + links, blocks = check() + except (DocumentationError, OSError, subprocess.CalledProcessError) as error: + print(f"FAIL: {error}", file=sys.stderr) + return 1 + print(f"PASS: {links} local Markdown links/anchors and {blocks} JSON/TOML examples verified.") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/plugins/codex-orchestration/test/test_docs.py b/plugins/codex-orchestration/test/test_docs.py new file mode 100644 index 0000000..5eb1edb --- /dev/null +++ b/plugins/codex-orchestration/test/test_docs.py @@ -0,0 +1,57 @@ +"""Regression coverage for the offline Markdown documentation checker.""" +from __future__ import annotations + +import importlib.util +from pathlib import Path +import subprocess +import tempfile +import unittest + + +PACKAGE = Path(__file__).resolve().parents[1] +SPEC = importlib.util.spec_from_file_location("docs_check", PACKAGE / "test/check_docs.py") +assert SPEC and SPEC.loader +docs_check = importlib.util.module_from_spec(SPEC) +SPEC.loader.exec_module(docs_check) + + +class DocumentationCheckerTests(unittest.TestCase): + def setUp(self) -> None: + self.temporary = tempfile.TemporaryDirectory(prefix="orchestration-docs-") + self.root = Path(self.temporary.name) + subprocess.run(["git", "init", "-q", str(self.root)], check=True) + + def tearDown(self) -> None: + self.temporary.cleanup() + + def write_tracked(self, relative: str, content: str) -> None: + file = self.root / relative + file.parent.mkdir(parents=True, exist_ok=True) + file.write_text(content, encoding="utf-8") + subprocess.run(["git", "-C", str(self.root), "add", relative], check=True) + + def test_rejects_missing_local_link(self) -> None: + self.write_tracked("README.md", "# Start\n[Missing](missing.md)\n") + with self.assertRaisesRegex(docs_check.DocumentationError, r"README.md:2: missing local link target"): + docs_check.check(self.root) + + def test_rejects_missing_local_anchor(self) -> None: + self.write_tracked("README.md", "# Start\n[Target](guide.md#not-here)\n") + self.write_tracked("guide.md", "# Elsewhere\n") + with self.assertRaisesRegex(docs_check.DocumentationError, r"README.md:2: missing local anchor"): + docs_check.check(self.root) + + def test_rejects_invalid_json_and_toml_examples(self) -> None: + for language, content in [("json", '{"enabled": }'), ("toml", "enabled =")]: + with self.subTest(language=language): + self.write_tracked("README.md", f"# Start\n```{language}\n{content}\n```\n") + with self.assertRaisesRegex(docs_check.DocumentationError, rf"README.md:3: invalid {language}"): + docs_check.check(self.root) + + def test_ignores_link_shaped_shell_text_inside_a_fence(self) -> None: + self.write_tracked("README.md", "# Start\n```sh\necho '[not-a-link](missing.md)'\n```\n") + self.assertEqual((0, 0), docs_check.check(self.root)) + + +if __name__ == "__main__": + unittest.main() diff --git a/plugins/codex-orchestration/test/test_package.py b/plugins/codex-orchestration/test/test_package.py index 7f8e9ae..9e100fa 100644 --- a/plugins/codex-orchestration/test/test_package.py +++ b/plugins/codex-orchestration/test/test_package.py @@ -75,7 +75,7 @@ def test_runtime_inventory_contains_no_caches_symlinks_or_personal_paths(self): if file.is_file(): data = file.read_bytes(); total += len(data) self.assertLessEqual(len(data), 1024*1024) - self.assertNotIn(b'/Users/ej', data) + self.assertNotIn(b'/Users/', data) self.assertLess(total, 1024*1024) def test_catalog_checker_accepts_valid_and_rejects_broken_integration(self): @@ -83,7 +83,7 @@ def test_catalog_checker_accepts_valid_and_rejects_broken_integration(self): root = Path(scratch) shutil.copytree(PACKAGE, root/'plugins/codex-orchestration', ignore=shutil.ignore_patterns('__pycache__')) file = root/'.agents/plugins/marketplace.json'; file.parent.mkdir(parents=True) - catalog = {'name':'codex-orchestration', 'plugins':[{'name':'codex-orchestration','source':{'source':'local','path':'./plugins/codex-orchestration'},'policy':{'installation':'AVAILABLE','authentication':'ON_INSTALL'},'category':'Productivity','version':'0.2.0'}]} + catalog = {'name':'codex-orchestration', 'plugins':[{'name':'codex-orchestration','source':{'source':'local','path':'./plugins/codex-orchestration'},'policy':{'installation':'AVAILABLE','authentication':'ON_INSTALL'},'category':'Productivity','version':'0.2.1'}]} file.write_text(json.dumps(catalog)); catalog_check.check(root) catalog['plugins'][0]['source']['path']='./missing' file.write_text(json.dumps(catalog)) @@ -92,7 +92,7 @@ def test_catalog_checker_accepts_valid_and_rejects_broken_integration(self): catalog['plugins'][0]['version']='9.9.9' file.write_text(json.dumps(catalog)) with self.assertRaises(AssertionError): catalog_check.check(root) - catalog['plugins'][0]['version']='0.2.0' + catalog['plugins'][0]['version']='0.2.1' catalog['plugins'].append(catalog['plugins'][0]) file.write_text(json.dumps(catalog)) with self.assertRaises(AssertionError): catalog_check.check(root)