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
2 changes: 1 addition & 1 deletion .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"name": "mzored",
"url": "https://github.com/mzored"
},
"description": "Outcome-first orchestration for Claude Code and Codex. Describe the product result; the agent chooses the engineering method and proves the outcome.",
"description": "Owner–agent contract for verified project outcomes, for Claude Code and Codex. Describe the product result; the agent owns the engineering method and must show fresh evidence before it reports completion.",
"plugins": [
{
"name": "skiphow",
Expand Down
64 changes: 49 additions & 15 deletions .github/workflows/pages.yml
Original file line number Diff line number Diff line change
@@ -1,32 +1,66 @@
name: Publish site
name: Repair site

# Manual recovery only. Ordinary publication happens in release.yml, from the
# exact validated tag. This workflow rebuilds the site artifact from one exact
# ref the operator names, so a repair never silently deploys moving default-branch
# content over a released site. It has no push trigger and refuses to run without
# a ref that is a release tag or a full commit SHA.

on:
workflow_dispatch:
inputs:
ref:
description: "Exact ref to deploy: a release tag (vMAJOR.MINOR.PATCH) or a 40-hex commit SHA"
required: true
type: string

permissions:
contents: read
pages: write
id-token: write

concurrency:
group: pages
cancel-in-progress: false
permissions: {}

jobs:
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
build:
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: read
steps:
- name: Refuse anything but an exact release tag or commit SHA
env:
REQUESTED_REF: ${{ inputs.ref }}
run: |
case "${REQUESTED_REF}" in
"") echo "ref is required" >&2; exit 1 ;;
esac
if ! printf '%s\n' "${REQUESTED_REF}" | grep -Eq '^(v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)|[0-9a-f]{40})$'; then
echo "ref must be an exact release tag or a 40-hex commit SHA, not a branch: ${REQUESTED_REF}" >&2
exit 1
fi
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ inputs.ref }}
persist-credentials: false
- uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0
- name: Record the exact commit being deployed
env:
REQUESTED_REF: ${{ inputs.ref }}
run: |
echo "Deploying site tree of ${REQUESTED_REF} at $(git rev-parse HEAD)"
- uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0
with:
path: site
- name: Deploy GitHub Pages

deploy:
needs: build
runs-on: ubuntu-latest
timeout-minutes: 5
permissions:
pages: write
id-token: write
concurrency:
group: pages
cancel-in-progress: false
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Deploy the site artifact built from the exact ref
id: deployment
uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5.0.0
93 changes: 84 additions & 9 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,20 +1,34 @@
name: Release

# Privilege separation, in order:
# validate contents: read runs every repository-controlled and third-party
# script (dependencies, check.py, the Codex validator),
# proves tag/VERSION/main ancestry, and uploads the
# release notes, the validation matrix, and the site
# tree as immutable artifacts of this exact tag commit.
# publish-release contents: write no checkout, no dependency install, no repository
# code; consumes the validated notes artifact only.
# deploy-site pages: write deploys the site artifact validate uploaded from the
# id-token: write same commit; runs no repository build script.
# A failed validate job produces neither a release nor a site deployment.

on:
push:
tags:
- "v*"

permissions:
contents: write
permissions: {}

jobs:
release:
validate:
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: read
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ github.sha }}
fetch-depth: 0
persist-credentials: false
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
Expand All @@ -28,17 +42,22 @@ jobs:
with:
python-version: "3.12"
- run: python -m pip install -r requirements-dev.txt
- run: python scripts/check.py
- run: python scripts/check_hosts.py --require-codex-validator --skip-install
env:
CODEX_PLUGIN_VALIDATOR: ${{ github.workspace }}/.codex-validator/codex-rs/skills/src/assets/samples/plugin-creator/scripts/validate_plugin.py
- name: Require the tag to match VERSION
run: |
test "v$(cat VERSION)" = "${GITHUB_REF_NAME}"
- name: Require the tag commit to be on main
run: |
git fetch --no-tags origin main
git merge-base --is-ancestor "${GITHUB_SHA}" origin/main
- name: Run the deterministic package gate and the host validators
run: |
python scripts/check_hosts.py \
--package-gate \
--require-codex-validator \
--skip-install \
--matrix-out release-validation-matrix.md
env:
CODEX_PLUGIN_VALIDATOR: ${{ github.workspace }}/.codex-validator/codex-rs/skills/src/assets/samples/plugin-creator/scripts/validate_plugin.py
- name: Extract release notes from CHANGELOG.md
run: |
awk -v version="$(cat VERSION)" '
Expand All @@ -47,8 +66,64 @@ jobs:
on { print }
' CHANGELOG.md > release-notes.md
test -s release-notes.md
- name: Create the GitHub release
printf '\n## Release validation matrix\n\n' >> release-notes.md
cat release-validation-matrix.md >> release-notes.md
- name: Upload the validated release notes
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: release-notes
path: release-notes.md
if-no-files-found: error
retention-days: 7
- name: Upload the validation matrix
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: release-validation-matrix
path: release-validation-matrix.md
if-no-files-found: error
retention-days: 90
- name: Upload the site tree of this exact tag
uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0
with:
path: site

publish-release:
needs: validate
runs-on: ubuntu-latest
timeout-minutes: 5
permissions:
contents: write
steps:
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: release-notes
- name: Create the GitHub release from the validated notes
env:
GH_TOKEN: ${{ github.token }}
run: |
gh release create "${GITHUB_REF_NAME}" --title "${GITHUB_REF_NAME}" --notes-file release-notes.md
test -s release-notes.md
gh release create "${GITHUB_REF_NAME}" \
--repo "${GITHUB_REPOSITORY}" \
--verify-tag \
--title "${GITHUB_REF_NAME}" \
--notes-file release-notes.md

deploy-site:
needs:
- validate
- publish-release
runs-on: ubuntu-latest
timeout-minutes: 5
permissions:
pages: write
id-token: write
concurrency:
group: pages
cancel-in-progress: false
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Deploy the site artifact validate uploaded
id: deployment
uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5.0.0
16 changes: 13 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,33 @@ Deletion comes first. Prefer removing a contradiction, clarifying intent, or mov

This is for the contributor acting on a review of their own change, not for the reviewer producing one. The shipped contract is prose, so a reviewer can always propose a different wording, and a review that is allowed to do so never ends. Treat what comes back as evidence to weigh, not a list to work through, and confirm every finding against the file yourself before acting on it. A reviewer that cannot point at the defect is reporting taste.

A finding qualifies when it names one of these: a factual error, including a number, a claim about what a file says, or a claim about how a host behaves; a contradiction with another shipped sentence or with `docs/decisions.md`; a module whose reason to consult it cannot be recognized without opening it; a claim presented as demonstrated that no receipt supports; a mandatory step, gate, or persistent state added without the evidence this file requires for one; or an authority, boundary, or portability error. Fix what qualifies, within the scope the change already carries, and record what it was.
A finding qualifies when it names one of these: a factual error, including a number, a claim about what a file says, or a claim about how a host behaves; a contradiction with another shipped sentence; a module whose reason to consult it cannot be recognized without opening it; a claim presented as demonstrated that no receipt supports; a mandatory step, gate, or persistent state added without the evidence this file requires for one; or an authority, boundary, or portability error. Fix what qualifies, within the scope the change already carries, and record what it was.

A finding does not qualify when it offers a rephrasing that changes no behavior, prefers a different degree of hedging, or says a sentence could be clearer without naming what breaks if it is not. Say so and leave the sentence alone. Neither the reviewer's confidence nor the length of its list is evidence.

Stop when a round returns only findings that do not qualify. Do not open another round to see whether it finds more, and do not re-review wording that survived a round unchanged. Improving instructions has no completion condition of its own; the observed defect is the completion condition.

## Evidence

Use current primary documentation for host behavior, plugin formats, and security guidance. Read `docs/decisions.md` before changing the product contract so old alternatives are not reopened without new evidence; it links the immutable archive of the earlier ADRs and research.
Use current primary documentation for host behavior, plugin formats, and security guidance. Read prior decisions to understand earlier constraints and avoid repeating settled analysis. Reopen a decision when current host behavior, model evidence, product goals, security boundaries, or maintenance cost materially changes its premises. `docs/decisions.md` opens with the index of live decisions and their premises; the sections under it are history and rebuttable context, not a veto, and it links the immutable archive of the earlier ADRs and research.

Model behavior is proven only by deliberate receipts from real runs made with the host's own permission and budget controls. A receipt worth keeping holds everything fixed but the package: a throwaway fixture repository, a session carrying only the candidate package and the host's own built-ins, and the same prompt on both sides of the change. Isolate Codex by pointing both its own home and the operating system's home directory at a scratch location, because it also reads a host-agnostic user skill directory that its own home setting does not cover, and Claude by disabling every setting source and passing the package as a session plugin, which leaves authentication alone. Prove the isolation with a control run, and confirm it in the session transcript rather than by asking the model what it can see, before trusting anything built on it. Disabling the setting sources keeps the maintainer's own instruction files out of a session's context but does not stop the session from reading them with a shell command, so search each transcript for those files as well as for the package. Run the failing case before the change as well as after it, because a run that only shows the new behavior proves the wording is compatible with it, not that it produced it.

Keep a receipt small, because its cost is not proportional to what it settles: the 2.16.1 pass answered one yes-or-no question with forty sessions across fifty-one invocations, $165 and nearly five hours, and the four sessions that carried the answer cost under six dollars between them. Name the observable before running and stop each session once it lands rather than when the task finishes; where the observable is what a run does at the dispatch, paying for the delegates to finish buys nothing and costs most of the run, and where it is what they return, it does not. Read what earlier receipts recorded about the prompt shape that produces the behavior, pilot one session per arm, then run one more per arm and stop; a third is for when the two disagree. Keep one fixture, and when the pilot does not produce the behavior at all, fix the prompt from the record rather than by running another batch. Set a spending limit per session and a ceiling for the whole receipt, cap the sessions in flight, give every run its own fixture directory and log because two sharing one destroy each other's evidence, and read transcript write times before calling a run stuck, because a root blocked on a delegate looks the same as a hang.

Summarize claims and durable source links in `docs/evidence.md`; do not add one research file per run or release. A behavior no receipt has shown stays `UNVERIFIED`. Deterministic checks and CI never start a model, and tests never create or delete a repository.

The behavioral corpus in `evals/` is arm-aware: every case states what must hold in every arm and what each arm may, must, and must not do, an arm with no package can never be required to produce a package-only event, and a case whose expectations no arm could satisfy is a defect the corpus tests catch. A paid run happens only on the owner's authorization under the limits recorded in the corpus, never from CI, and a passing corpus test moves nothing toward `Observed`.

## Writing instructions for the model

The shipped text and every delegate brief follow one prompt standard. State the goal, the context that settles it, the authority granted, the constraints, what success looks like, and what to report, in that order and in plain declarative sentences. Put the durable material first and the request last in a long prompt. Prefer a positive instruction to a prohibition and give the reason where one exists; use an example only where the shape is otherwise ambiguous; do not list steps where a capable model would infer them; name the observable rather than the process. Ask the model to reason only where the task warrants it, and route model and effort by the task's consequence and complexity rather than by a fixed tier. Remove a sentence that cannot be shown to change what a capable agent does. Do not assert how models in general behave without a source that shows it.

## Checks

Install the pinned dependencies with `python -m pip install -r requirements-dev.txt`; the checks install nothing and stop on an interpreter that misses a pin. Run focused tests through `python scripts/check.py --pytest <pytest-arguments>`. Before completion, run `python scripts/check.py` and `git diff --check`. For packaging changes, also run `python scripts/check_hosts.py` and report an unavailable host as `UNVERIFIED`. `scripts/check.py` validates the single owner skill, its reachable modules and resources, the continuity hook, aligned versions, and portability boundaries such as personal paths and versioned model IDs. Change the check and `docs/decisions.md` together when those invariants change. A deterministic check protects a compatibility or safety property, not editorial wording: do not pin a method roster, role set, or prose budget.
Install the pinned dependencies with `python -m pip install -r requirements-dev.txt`; the checks install nothing and stop on an interpreter that misses a pin. Run focused tests through `python scripts/check.py --pytest <pytest-arguments>`. Before completion, run `python scripts/check.py` and `git diff --check`. For packaging changes, also run `python scripts/check_hosts.py`, which reports each host capability on its own row, and report an unavailable host as `UNVERIFIED`. `scripts/check.py` validates the single owner skill, its reachable modules and resources, the safety shape of any shipped hook, aligned versions, and portability boundaries such as personal paths and versioned model IDs. Change the check and `docs/decisions.md` together when those invariants change.

Every deterministic assertion belongs to one class: a package or host contract, a security or release invariant, or the semantic validity of the behavioral corpus, all of which fail the run; or an editorial or layout preference, which is at most a non-blocking lint; or an assumption about the current shape, which is deleted unless it is promoted into a stated contract with a reason. Do not pin a marketing sentence, a method roster or count, a role set, a hook matcher topology, a site presentation detail, or a prose budget with no measured limit behind it.

## Versioning and releases

Expand All @@ -48,6 +56,8 @@ Decide the number after the change is complete and its compatibility is known. D

Release one coherent, verified change set at a time. Bump `VERSION` and both manifests once, at the start of the branch that will carry the release, and keep that number through the branch; related work accumulates there rather than as a sequence of releases on `main`. Never edit or re-tag a released version. Claim a material change in model behavior only after receipts.

Every release publishes the compact validation matrix, one row per capability: the deterministic package gate, Codex and Claude schema validation, clean install on each host, explicit invocation, implicit activation, continuity, and the behavioral suite, each `PASS`, `FAIL`, `UNVERIFIED`, or `Observed`, with the behavioral row pointing at `docs/evidence.md` and never implied by CI. A skipped check stays visible as `UNVERIFIED`; it never disappears into a green aggregate.

## Portability and safety

Do not add personal paths, home-directory assumptions, credentials, telemetry, or network calls to the package or its checks. Keep provider model IDs out of the shared skill policy. Bump `VERSION` whenever `plugins/skiphow/` changes.
Loading