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
53 changes: 53 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
name: CI

on:
pull_request:
push:
branches:
- main

permissions:
contents: read

jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: "3.12"

- uses: pnpm/action-setup@v4
with:
version: "11.11.0"

- uses: actions/setup-node@v4
with:
node-version: "24.15.0"
cache: pnpm

- uses: oven-sh/setup-bun@v2
with:
bun-version: "1.3.13"

- run: pnpm install --frozen-lockfile

- name: Run Python validation
run: |
pnpm test:python
python3 plugins/pstack-codex/scripts/validate_port.py

- name: Run bundled pstack tests
working-directory: plugins/pstack-codex/skills/poteto-mode/scripts
env:
GIT_CONFIG_NOSYSTEM: "1"
GIT_CONFIG_GLOBAL: /dev/null
GIT_AUTHOR_NAME: pstack-ci
GIT_AUTHOR_EMAIL: pstack-ci@invalid
GIT_COMMITTER_NAME: pstack-ci
GIT_COMMITTER_EMAIL: pstack-ci@invalid
run: |
bun install --frozen-lockfile
bun test orch watch-pr
65 changes: 65 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
name: Release

on:
push:
branches:
- main

permissions:
contents: write
issues: write
pull-requests: write

concurrency:
group: semantic-release
cancel-in-progress: false

jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- uses: actions/setup-python@v5
with:
python-version: "3.12"

- uses: pnpm/action-setup@v4
with:
version: "11.11.0"

- uses: actions/setup-node@v4
with:
node-version: "24.15.0"
cache: pnpm

- uses: oven-sh/setup-bun@v2
with:
bun-version: "1.3.13"

- run: pnpm install --frozen-lockfile

- name: Run Python validation
run: |
pnpm test:python
python3 plugins/pstack-codex/scripts/validate_port.py

- name: Run bundled pstack tests
working-directory: plugins/pstack-codex/skills/poteto-mode/scripts
env:
GIT_CONFIG_NOSYSTEM: "1"
GIT_CONFIG_GLOBAL: /dev/null
GIT_AUTHOR_NAME: pstack-release
GIT_AUTHOR_EMAIL: pstack-release@invalid
GIT_COMMITTER_NAME: pstack-release
GIT_COMMITTER_EMAIL: pstack-release@invalid
run: |
bun install --frozen-lockfile
bun test orch watch-pr

- name: Publish semantic release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: pnpm release
25 changes: 25 additions & 0 deletions .releaserc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"branches": ["main"],
"tagFormat": "v${version}",
"plugins": [
[
"@semantic-release/commit-analyzer",
{
"preset": "conventionalcommits"
}
],
[
"@semantic-release/release-notes-generator",
{
"preset": "conventionalcommits"
}
],
[
"@semantic-release/exec",
{
"verifyReleaseCmd": "python3 plugins/pstack-codex/scripts/validate_release.py --tag v${nextRelease.version}"
}
],
"@semantic-release/github"
]
}
34 changes: 34 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Changelog

All notable changes to pstack-codex are documented here. Release versions and
notes are calculated from Conventional Commits and verified by semantic-release.

## 1.0.0 (2026-08-31)

### Features

- Port all 45 pstack skills to Codex-native skill packages.
- Add the adversarial-review skill with skeptic, architecture, and minimalism lenses.
- Register five custom Codex agents: `poteto-agent`, `comment-sicko`,
`pstack_skeptic`, `pstack_architect`, and `pstack_minimalist`.
- Add marketplace installation, structural validation, isolated evals, and live
persistent-parent agent smoke tests.
- Add semantic-release version verification, release notes, GitHub releases,
contributor attribution, and pull-request validation.

### Bug Fixes

- Restore missing source references required by the ported skills.
- Translate Cursor-specific commands and assumptions to Codex-native behavior.
- Document and validate the Codex project-trust requirement for custom agents.
- Make custom-agent definitions self-contained and verify all named agents spawn.
- Replace ephemeral agent-smoke parents with durable Codex tasks.
- Align the changelog preset and accept generated and linked semantic-release headings.

### Contributors

- [Lauren Tan (@poteto)](https://github.com/poteto)
- [Cursor Agent (@cursoragent)](https://github.com/cursoragent)
- [Hashem Khalifa (@HashemKhalifa)](https://github.com/HashemKhalifa)

[1.0.0]: https://github.com/HashemKhalifa/pstack-codex/releases/tag/v1.0.0
18 changes: 18 additions & 0 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Contributors

## Upstream

- [Lauren Tan (`@poteto`)](https://github.com/poteto) created pstack and the
original adversarial-review workflow and is the primary upstream author.
- [Cursor Agent (`@cursoragent`)](https://github.com/cursoragent) contributed
commits under the upstream `cursor/plugins/pstack` path.

## Codex port

- [Hashem Khalifa (`@HashemKhalifa`)](https://github.com/HashemKhalifa)
created and maintains the independent Codex port, packaging, validation,
custom-agent integration, and release automation.

Contributor identities are derived from the public Git history of the exact
upstream source paths and this repository. Upstream work remains under the MIT
license recorded in [`LICENSE`](LICENSE).
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# pstack-codex

[![CI](https://github.com/HashemKhalifa/pstack-codex/actions/workflows/ci.yml/badge.svg)](https://github.com/HashemKhalifa/pstack-codex/actions/workflows/ci.yml)
[![GitHub release](https://img.shields.io/github/v/release/HashemKhalifa/pstack-codex)](https://github.com/HashemKhalifa/pstack-codex/releases)
[![semantic-release](https://img.shields.io/badge/semantic--release-conventionalcommits-e10079?logo=semantic-release)](https://github.com/semantic-release/semantic-release)

A complete Codex port of Cursor's verified pstack marketplace package, plus a
Codex-safe fork of `poteto/noodle`'s adversarial-review skill.

Expand Down Expand Up @@ -67,6 +71,20 @@ agents, required upstream resources, Codex frontmatter, port-contract
references, and validation evidence are present. The smoke command is the live
terminal gate: every named agent must be discovered and successfully spawned.

## Releases and changelog

[`semantic-release`](https://github.com/semantic-release/semantic-release)
analyzes Conventional Commits merged to `main`, selects and verifies the next
SemVer version recorded by the release PR, tags the release, and publishes the
GitHub Release. See [`CHANGELOG.md`](CHANGELOG.md) for the release history and
[`RELEASING.md`](RELEASING.md) for the PR-only release workflow.

## Contributors

Upstream authors and Codex-port maintainers are recorded in
[`CONTRIBUTORS.md`](CONTRIBUTORS.md). The list is derived from the public Git
history of the exact imported paths.

## Safety and portability

Read [`plugins/pstack-codex/CODEX_PORT.md`](plugins/pstack-codex/CODEX_PORT.md).
Expand Down
36 changes: 36 additions & 0 deletions RELEASING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Releasing pstack-codex

Releases follow Semantic Versioning and are generated by
[`semantic-release`](https://github.com/semantic-release/semantic-release).

## Commit convention

- `fix:` produces a patch release.
- `feat:` produces a minor release.
- `BREAKING CHANGE:` in the commit footer produces a major release.
- `docs:`, `test:`, `build:`, `ci:`, and `chore:` do not release by default.

## Workflow

1. Work from the canonical clone of this repository on a branch.
2. Add user-visible changes with Conventional Commit messages.
3. Run the structural, script, and live-agent gates, then run semantic-release
in dry-run mode to calculate the next version.
4. Add that version's grouped notes to `CHANGELOG.md` and update the plugin
manifest with:

```sh
python3 plugins/pstack-codex/scripts/validate_release.py --set-version X.Y.Z
```

5. Re-run the release dry-run; it must verify the changelog and manifest against
the calculated tag.
6. Open a pull request with validation evidence. Never push fixes directly to
`main`.
7. Merge the accepted PR after required checks and review threads are complete.
8. The `Release` workflow independently recalculates and verifies that version,
creates the `vX.Y.Z` tag, and publishes the GitHub Release. It never pushes a
generated commit directly to `main`.

The first qualifying merge creates `v1.0.0`. Later versions are determined
strictly from commit impact.
22 changes: 22 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "pstack-codex-release",
"version": "0.0.0-development",
"private": true,
"description": "Release automation for the pstack-codex plugin bundle",
"packageManager": "pnpm@11.11.0",
"engines": {
"node": "^22.22.2 || >=24.15.0"
},
"scripts": {
"release": "semantic-release",
"test:python": "python3 -m unittest discover -s plugins/pstack-codex/scripts -p 'test_*.py'"
},
"devDependencies": {
"@semantic-release/commit-analyzer": "13.0.1",
"@semantic-release/exec": "7.1.0",
"@semantic-release/github": "12.0.9",
"@semantic-release/release-notes-generator": "14.1.1",
"conventional-changelog-conventionalcommits": "9.3.1",
"semantic-release": "25.0.9"
}
}
2 changes: 1 addition & 1 deletion plugins/pstack-codex/.codex-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "pstack-codex",
"version": "0.14.5+codex.20260831113459",
"version": "1.0.0",
"description": "A complete, safety-scoped Codex port of pstack's 45 rigorous engineering workflows.",
"author": {
"name": "Lauren Tan and local Codex adaptation"
Expand Down
76 changes: 76 additions & 0 deletions plugins/pstack-codex/scripts/test_validate_release.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
from pathlib import Path
import sys
import tempfile
import unittest

sys.path.insert(0, str(Path(__file__).resolve().parent))

from validate_release import extract_release_notes, set_manifest_version, validate_release


class ValidateReleaseTest(unittest.TestCase):
def test_version_and_changelog_match_tag(self) -> None:
with tempfile.TemporaryDirectory() as temp_dir:
root = Path(temp_dir)
manifest = root / "plugins" / "pstack-codex" / ".codex-plugin"
manifest.mkdir(parents=True)
(manifest / "plugin.json").write_text(
'{"name":"pstack-codex","version":"1.0.0"}\n'
)
(root / "CHANGELOG.md").write_text(
"# Changelog\n\n## 1.0.0 (2026-08-31)\n\n### Added\n\n- Live agent smoke.\n"
)
self.assertEqual([], validate_release(root, "v1.0.0"))
self.assertIn(
"### Added",
extract_release_notes(
(root / "CHANGELOG.md").read_text(), "1.0.0"
),
)

def test_set_manifest_version_preserves_other_fields(self) -> None:
with tempfile.TemporaryDirectory() as temp_dir:
root = Path(temp_dir)
manifest = root / "plugins" / "pstack-codex" / ".codex-plugin"
manifest.mkdir(parents=True)
path = manifest / "plugin.json"
path.write_text(
'{"name":"pstack-codex","version":"0.0.0-development","skills":"./skills/"}\n'
)
set_manifest_version(root, "1.2.3")
contents = path.read_text()
self.assertIn('"version": "1.2.3"', contents)
self.assertIn('"skills": "./skills/"', contents)

def test_extract_release_notes_accepts_linked_version_heading(self) -> None:
changelog = (
"# Changelog\n\n"
"## [1.1.0](https://github.com/HashemKhalifa/pstack-codex/compare/"
"v1.0.0...v1.1.0) (2026-09-01)\n\n"
"### Bug Fixes\n\n"
"- Accept semantic-release compare links.\n\n"
"## 1.0.0 (2026-08-31)\n"
)

notes = extract_release_notes(changelog, "1.1.0")

self.assertIn("## [1.1.0]", notes)
self.assertIn("### Bug Fixes", notes)
self.assertNotIn("## 1.0.0", notes)

def test_mismatch_fails_closed(self) -> None:
with tempfile.TemporaryDirectory() as temp_dir:
root = Path(temp_dir)
manifest = root / "plugins" / "pstack-codex" / ".codex-plugin"
manifest.mkdir(parents=True)
(manifest / "plugin.json").write_text(
'{"name":"pstack-codex","version":"1.0.1"}\n'
)
(root / "CHANGELOG.md").write_text("# Changelog\n")
errors = validate_release(root, "v1.0.0")
self.assertTrue(any("manifest version" in error for error in errors))
self.assertTrue(any("changelog" in error for error in errors))


if __name__ == "__main__":
unittest.main()
Loading
Loading