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
58 changes: 58 additions & 0 deletions .codex/skills/guardex-merge-skills-to-dev/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
---
name: guardex-merge-skills-to-dev
description: "Use when you need to merge SKILL.md updates from agent branches/worktrees into the local base branch (default: dev) with the multiagent-safety flow."
---

# GuardeX Merge Skills to dev

Use this skill when you only want to promote Codex skill file updates into the base branch (normally `dev`) without editing the visible base checkout directly.

## What this merges

- `.codex/skills/**/SKILL.md`
- `templates/codex/skills/**/SKILL.md`

## Merge runbook (safe path)

1. Resolve the base branch:

```sh
BASE_BRANCH="$(git config --get multiagent.baseBranch || echo dev)"
echo "$BASE_BRANCH"
```

2. Start a dedicated integration sandbox from base:

```sh
bash scripts/agent-branch-start.sh "merge-skill-files-to-${BASE_BRANCH}" "skill-merge" "$BASE_BRANCH"
```

3. Enter the sandbox worktree printed by the command above.

4. Pull only skill files from each source agent branch:

```sh
SOURCE_BRANCH="<agent-branch>"
git checkout "$SOURCE_BRANCH" -- ':(glob).codex/skills/**/SKILL.md' ':(glob)templates/codex/skills/**/SKILL.md'
```

5. Verify scope before commit:

```sh
git status --short
git diff --name-only
```

6. Commit and merge back to base using guardex finish flow:

```sh
git add .codex/skills templates/codex/skills
git commit -m "Merge skill file updates into ${BASE_BRANCH}"
bash scripts/agent-branch-finish.sh --branch "$(git rev-parse --abbrev-ref HEAD)" --base "$BASE_BRANCH" --via-pr --wait-for-merge --cleanup
```

## Notes

- If a source branch has non-skill changes, this runbook keeps them out of the merge.
- If merge conflicts occur, resolve only within the skill files, then rerun `agent-branch-finish.sh`.
- Do not commit directly on `dev`/`main`; always merge through an agent branch/worktree.
48 changes: 1 addition & 47 deletions .codex/skills/guardex/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,51 +33,5 @@ gx scan
- Prefer `gx doctor` for one-step repair + verification.
- Keep agent work isolated (`agent/*` branches + lock claims).
- For one-command Codex sandbox startup, use `bash scripts/codex-agent.sh "<task>" "<agent-name>"`.
- For skill-file-only merges into the local base branch (`dev` by default), use `$guardex-merge-skills-to-dev`.
- Do not bypass protected branch safeguards unless explicitly required.

## Bulk merge runbook (changed agent branches)

Use this when a repo has many `agent/*` branches/worktrees with pending changes and you need them merged into the base branch quickly.

1. Confirm base and guardrails are healthy:

```sh
git status --short --branch
git pull --ff-only origin "$(git config --get multiagent.baseBranch || echo dev)"
gx scan
```

2. Run bulk finish first:

```sh
gx finish --all
```

3. If a branch fails with `already used by worktree` or stale rebase hints, clear stale state in that worktree, then retry targeted finish:

```sh
git -C "<worktree>" rebase --abort || true
gx finish --branch "<agent-branch>" --base "$(git config --get multiagent.baseBranch || echo dev)" --no-wait-for-merge --cleanup
```

4. If `gh pr merge` exits non-zero due local branch deletion but PR is already merged, verify with:

```sh
gh pr view "<pr-number>" --json state,mergedAt,url
```

5. If a branch is still ahead of base with no open PR, create and merge a follow-up PR manually:

```sh
gh pr create --base "<base-branch>" --head "<agent-branch>" --title "Auto-finish: <agent-branch>" --body "Follow-up merge for pending branch commits."
gh pr merge "<pr-number>" --squash --delete-branch
```

6. Final verification:

```sh
gh pr list --state open --search "head:agent/ base:<base-branch>"
git pull --ff-only origin "<base-branch>"
gx cleanup
gx scan
```
21 changes: 21 additions & 0 deletions .github/workflows/cr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: Code Review

on:
pull_request:
types: [opened, reopened, synchronize]

permissions:
contents: read
pull-requests: write

jobs:
review:
if: ${{ secrets.OPENAI_API_KEY != '' }}
runs-on: ubuntu-latest
steps:
- uses: anc95/ChatGPT-CodeReview@main
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
OPENAI_API_ENDPOINT: https://api.openai.com/v1
MODEL: gpt-4o-mini
36 changes: 36 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,40 @@ gh --version
gh auth status
```

## Optional GitHub Apps: fork sync + PR review

### Pull app (Probot fork sync)

GuardeX setup now installs a starter file at `.github/pull.yml.example`.

To enable fork auto-sync:

```sh
cp .github/pull.yml.example .github/pull.yml
```

Then edit `.github/pull.yml`:

- set `rules[].base` to your fork branch (`main`, `master`, or `dev`)
- set `rules[].upstream` to `<upstream-owner>:<branch>`

Install the app: <https://github.com/apps/pull>
Validate config: `https://pull.git.ci/check/<owner>/<repo>`

### CR-GPT code review app

Install app: <https://github.com/apps/cr-gpt>

`gx setup` also installs `.github/workflows/cr.yml` (GitHub Actions review workflow).

Then in your repo:

1. `Settings -> Secrets and variables -> Actions`
2. open `Variables`
3. add `OPENAI_API_KEY`

After that, the app reviews new and updated pull requests automatically.

## Companion dependency: `codex-auth` account switcher

For multi-identity Codex workflows, GuardeX pairs with
Expand Down Expand Up @@ -276,6 +310,8 @@ scripts/openspec/init-plan-workspace.sh
.githooks/pre-push
.codex/skills/guardex/SKILL.md
.claude/commands/guardex.md
.github/pull.yml.example
.github/workflows/cr.yml
.omx/state/agent-file-locks.json
```

Expand Down
27 changes: 27 additions & 0 deletions bin/multiagent-safety.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,10 @@ const TEMPLATE_FILES = [
'githooks/pre-commit',
'githooks/pre-push',
'codex/skills/guardex/SKILL.md',
'codex/skills/guardex-merge-skills-to-dev/SKILL.md',
'claude/commands/guardex.md',
'github/pull.yml.example',
'github/workflows/cr.yml',
];

const EXECUTABLE_RELATIVE_PATHS = new Set([
Expand Down Expand Up @@ -97,6 +100,7 @@ const MANAGED_GITIGNORE_PATHS = [
'.githooks/pre-push',
'oh-my-codex/',
'.codex/skills/guardex/SKILL.md',
'.codex/skills/guardex-merge-skills-to-dev/SKILL.md',
'.claude/commands/guardex.md',
LOCK_FILE_RELATIVE,
];
Expand Down Expand Up @@ -230,6 +234,25 @@ const AI_SETUP_PROMPT = `Use this exact checklist to setup GuardeX (Guardian T-R

11) Optional (GitHub remote cleanup): enable:
Settings -> General -> Pull Requests -> Automatically delete head branches

12) Optional (fork sync with Pull app):
cp .github/pull.yml.example .github/pull.yml
# then edit .github/pull.yml:
# - set rules[].base to your fork branch (main/master/dev)
# - set rules[].upstream to upstream-owner:branch
# install app: https://github.com/apps/pull
# validate config: https://pull.git.ci/check/<owner>/<repo>

13) Optional (PR review bot with cr-gpt GitHub App):
- install app: https://github.com/apps/cr-gpt
- in GitHub repo Settings -> Secrets and variables -> Actions -> Variables:
add OPENAI_API_KEY (your API key)
- the app reviews new/updated pull requests automatically

14) Optional: test PR review action workflow
- gx setup installs .github/workflows/cr.yml
- open or update a PR
- check Actions -> "Code Review" run logs + PR timeline comments
`;

const AI_SETUP_COMMANDS = `npm i -g @imdeadpool/guardex
Expand All @@ -249,6 +272,7 @@ openspec update
gx protect add release staging
gx sync --check
gx sync
cp .github/pull.yml.example .github/pull.yml
`;

const SCORECARD_RISK_BY_CHECK = {
Expand Down Expand Up @@ -452,6 +476,9 @@ function toDestinationPath(relativeTemplatePath) {
if (relativeTemplatePath.startsWith('claude/')) {
return `.${relativeTemplatePath}`;
}
if (relativeTemplatePath.startsWith('github/')) {
return `.${relativeTemplatePath}`;
}
throw new Error(`Unsupported template path: ${relativeTemplatePath}`);
}

Expand Down
58 changes: 58 additions & 0 deletions templates/codex/skills/guardex-merge-skills-to-dev/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
---
name: guardex-merge-skills-to-dev
description: "Use when you need to merge SKILL.md updates from agent branches/worktrees into the local base branch (default: dev) with the multiagent-safety flow."
---

# GuardeX Merge Skills to dev

Use this skill when you only want to promote Codex skill file updates into the base branch (normally `dev`) without editing the visible base checkout directly.

## What this merges

- `.codex/skills/**/SKILL.md`
- `templates/codex/skills/**/SKILL.md`

## Merge runbook (safe path)

1. Resolve the base branch:

```sh
BASE_BRANCH="$(git config --get multiagent.baseBranch || echo dev)"
echo "$BASE_BRANCH"
```

2. Start a dedicated integration sandbox from base:

```sh
bash scripts/agent-branch-start.sh "merge-skill-files-to-${BASE_BRANCH}" "skill-merge" "$BASE_BRANCH"
```

3. Enter the sandbox worktree printed by the command above.

4. Pull only skill files from each source agent branch:

```sh
SOURCE_BRANCH="<agent-branch>"
git checkout "$SOURCE_BRANCH" -- ':(glob).codex/skills/**/SKILL.md' ':(glob)templates/codex/skills/**/SKILL.md'
```

5. Verify scope before commit:

```sh
git status --short
git diff --name-only
```

6. Commit and merge back to base using guardex finish flow:

```sh
git add .codex/skills templates/codex/skills
git commit -m "Merge skill file updates into ${BASE_BRANCH}"
bash scripts/agent-branch-finish.sh --branch "$(git rev-parse --abbrev-ref HEAD)" --base "$BASE_BRANCH" --via-pr --wait-for-merge --cleanup
```

## Notes

- If a source branch has non-skill changes, this runbook keeps them out of the merge.
- If merge conflicts occur, resolve only within the skill files, then rerun `agent-branch-finish.sh`.
- Do not commit directly on `dev`/`main`; always merge through an agent branch/worktree.
1 change: 1 addition & 0 deletions templates/codex/skills/guardex/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ gx scan
- For one-command Codex sandbox startup, use `bash scripts/codex-agent.sh "<task>" "<agent-name>"`.
- `scripts/codex-agent.sh` auto-syncs the sandbox branch against base before each task and auto-finishes merge/PR flow after Codex exits.
- Auto-finish keeps the branch/worktree by default; remove merged branches explicitly with `gx cleanup` (or `gx cleanup --branch "<agent-branch>"`).
- For skill-file-only merges into the local base branch (`dev` by default), use `$guardex-merge-skills-to-dev`.
- Do not bypass protected branch safeguards unless explicitly required.

## Bulk merge runbook (changed agent branches)
Expand Down
6 changes: 6 additions & 0 deletions templates/github/pull.yml.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
version: "1"
rules:
- base: main
upstream: upstream-owner:main
mergeMethod: hardreset
mergeUnstable: true
21 changes: 21 additions & 0 deletions templates/github/workflows/cr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: Code Review

on:
pull_request:
types: [opened, reopened, synchronize]

permissions:
contents: read
pull-requests: write

jobs:
review:
if: ${{ secrets.OPENAI_API_KEY != '' }}
runs-on: ubuntu-latest
steps:
- uses: anc95/ChatGPT-CodeReview@main
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
OPENAI_API_ENDPOINT: https://api.openai.com/v1
MODEL: gpt-4o-mini
20 changes: 15 additions & 5 deletions test/install.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,10 @@ test('setup provisions workflow files and repo config', () => {
'.githooks/pre-commit',
'.githooks/pre-push',
'.codex/skills/guardex/SKILL.md',
'.codex/skills/guardex-merge-skills-to-dev/SKILL.md',
'.claude/commands/guardex.md',
'.github/pull.yml.example',
'.github/workflows/cr.yml',
'.omx/state/agent-file-locks.json',
'.gitignore',
'AGENTS.md',
Expand All @@ -282,11 +285,11 @@ test('setup provisions workflow files and repo config', () => {
assert.equal(fs.existsSync(path.join(repoDir, relativePath)), true, `${relativePath} missing`);
}

const guardexSkill = fs.readFileSync(path.join(repoDir, '.codex', 'skills', 'guardex', 'SKILL.md'), 'utf8');
assert.match(guardexSkill, /Bulk merge runbook \(changed agent branches\)/);
assert.match(guardexSkill, /gx finish --all/);
assert.match(guardexSkill, /gh pr create --base/);
assert.match(guardexSkill, /gh pr merge "<pr-number>" --squash --delete-branch/);
const crWorkflow = fs.readFileSync(path.join(repoDir, '.github', 'workflows', 'cr.yml'), 'utf8');
assert.match(crWorkflow, /name:\s+Code Review/);
assert.match(crWorkflow, /pull_request:/);
assert.match(crWorkflow, /OPENAI_API_KEY/);
assert.match(crWorkflow, /anc95\/ChatGPT-CodeReview@main/);

const packageJson = JSON.parse(fs.readFileSync(path.join(repoDir, 'package.json'), 'utf8'));
assert.equal(packageJson.scripts['agent:codex'], 'bash ./scripts/codex-agent.sh');
Expand Down Expand Up @@ -318,6 +321,7 @@ test('setup provisions workflow files and repo config', () => {
assert.match(gitignoreContent, /\.omx\//);
assert.match(gitignoreContent, /oh-my-codex\//);
assert.match(gitignoreContent, /\.codex\/skills\/guardex\/SKILL\.md/);
assert.match(gitignoreContent, /\.codex\/skills\/guardex-merge-skills-to-dev\/SKILL\.md/);
assert.match(gitignoreContent, /\.claude\/commands\/guardex\.md/);
assert.match(gitignoreContent, /\.omx\/state\/agent-file-locks\.json/);
assert.match(gitignoreContent, /# multiagent-safety:END/);
Expand Down Expand Up @@ -2950,6 +2954,11 @@ test('copy-prompt outputs AI setup instructions', () => {
assert.match(result.stdout, /OpenSpec default change flow \(core profile\)/);
assert.match(result.stdout, /\/opsx:propose <change-name>/);
assert.match(result.stdout, /openspec config profile <profile-name>/);
assert.match(result.stdout, /fork sync with Pull app/);
assert.match(result.stdout, /https:\/\/github.com\/apps\/pull/);
assert.match(result.stdout, /https:\/\/github.com\/apps\/cr-gpt/);
assert.match(result.stdout, /OPENAI_API_KEY/);
assert.match(result.stdout, /\.github\/workflows\/cr\.yml/);
assert.match(result.stdout, /scripts\/agent-file-locks.py claim/);
assert.match(result.stdout, /For every new user message\/task, repeat the same cycle/);
});
Expand All @@ -2965,6 +2974,7 @@ test('copy-commands outputs command-only checklist', () => {
assert.match(result.stdout, /scripts\/agent-file-locks.py claim/);
assert.match(result.stdout, /^openspec config profile <profile-name>$/m);
assert.match(result.stdout, /^openspec update$/m);
assert.match(result.stdout, /^cp \.github\/pull\.yml\.example \.github\/pull\.yml$/m);
assert.match(result.stdout, /gx sync --check/);
assert.doesNotMatch(result.stdout, /Use this exact checklist/);
});
Expand Down