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
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
[![CodeQL](https://img.shields.io/github/actions/workflow/status/recodeee/gitguardex/codeql.yml?branch=main&label=CodeQL)](https://github.com/recodeee/gitguardex/actions/workflows/codeql.yml)
[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/recodeee/gitguardex/badge)](https://securityscorecards.dev/viewer/?uri=github.com/recodeee/gitguardex)

[about_description.txt](./about_description.txt)

Guardian T-Rex for your multi-agent repo. Isolated worktrees, file locks, and PR-only merges stop parallel Codex & Claude agents from overwriting each other's work. Auto-wires Oh My Codex, Oh My Claude, OpenSpec, and Caveman.

**GitGuardex is a safety layer for parallel agent work in git repos.** If you're running more than one Codex or Claude agent on the same codebase, this is what keeps them from deleting each other's work.

> [!WARNING]
Expand All @@ -28,6 +32,8 @@ I was running ~30 Codex agents in parallel and hit a wall: they kept working on

### Solution

![Agent branch/worktree start protocol](https://raw.githubusercontent.com/recodeee/gitguardex/main/docs/images/workflow-branch-start.svg)

GitGuardex exists to stop that loop. Every agent gets its own worktree, claims the files it's touching, and can't clobber files another agent has claimed. Your local branch stays clean; agents stay in their lanes.


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,21 @@
## 2. Tests

- [x] 2.1 Update targeted install/self-update/status expectations for the renamed package.
- [x] 2.2 Restore post-rename regression coverage for branded doctor output, README canonical copy, and runtime/template parity.

## 3. Implementation

- [x] 3.1 Rename the published package metadata to `@imdeadpool/gitguardex`.
- [x] 3.2 Refresh CLI install prompts and package-name-dependent surfaces.
- [x] 3.3 Refresh README, tutorial/docs copy, and README-linked assets to use GitGuardex npm/install wording.
- [x] 3.4 Repair post-rename regressions in README structure, branded doctor-output assertions, and `codex-agent` runtime parity.

## 4. Verification

- [x] 4.1 Run renamed-package verification (`node --test --test-name-pattern "(self-update verifies on-disk version after @latest install and retries with pinned version when stale|self-update restarts into the installed CLI after a successful on-disk upgrade|status --json returns cli, services, and repo summary|prompt outputs AI setup instructions|prompt --exec outputs command-only checklist|deprecated copy-commands alias still works and warns)" test/install.test.js`, `node --check bin/multiagent-safety.js`, `npm pack --dry-run`). Result: targeted renamed-package tests passed `6/6`; `node --check bin/multiagent-safety.js` passed; `npm pack --dry-run` produced `imdeadpool-gitguardex-7.0.16.tgz`.
- [x] 4.2 Run `openspec validate agent-codex-rename-npm-package-to-gitguardex-everywh-2026-04-21-21-02 --type change --strict`. Result: `Change 'agent-codex-rename-npm-package-to-gitguardex-everywh-2026-04-21-21-02' is valid`.
- [x] 4.3 Run `openspec validate --specs`. Result: `No items found to validate.`
- [x] 4.4 Re-run the affected metadata/install assertions plus `npm test` after the post-rename regression repair and record the results. Result: `diff -u templates/scripts/codex-agent.sh scripts/codex-agent.sh` passed; `node --check bin/multiagent-safety.js` passed; `openspec validate agent-codex-rename-npm-package-to-gitguardex-everywh-2026-04-21-21-02 --type change --strict` passed; `openspec validate --specs` returned `No items found to validate.`; targeted regression rerun passed `3/3`; full `npm test` passed `161/161`.

## 5. Cleanup

Expand Down
51 changes: 51 additions & 0 deletions scripts/codex-agent.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ AGENT_NAME="${GUARDEX_AGENT_NAME:-agent}"
BASE_BRANCH="${GUARDEX_BASE_BRANCH:-}"
BASE_BRANCH_EXPLICIT=0
CODEX_BIN="${GUARDEX_CODEX_BIN:-codex}"
NODE_BIN="${GUARDEX_NODE_BIN:-node}"
AUTO_FINISH_RAW="${GUARDEX_CODEX_AUTO_FINISH:-true}"
AUTO_REVIEW_ON_CONFLICT_RAW="${GUARDEX_CODEX_AUTO_REVIEW_ON_CONFLICT:-true}"
AUTO_CLEANUP_RAW="${GUARDEX_CODEX_AUTO_CLEANUP:-true}"
Expand Down Expand Up @@ -143,6 +144,7 @@ if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
exit 1
fi
repo_root="$(git rev-parse --show-toplevel)"
active_session_state_script="${repo_root}/scripts/agent-session-state.js"

guardex_env_helper="${repo_root}/scripts/guardex-env.sh"
if [[ -f "$guardex_env_helper" ]]; then
Expand Down Expand Up @@ -446,6 +448,40 @@ has_origin_remote() {
git -C "$repo_root" remote get-url origin >/dev/null 2>&1
}

run_active_session_state() {
local action="$1"
shift

if [[ ! -f "$active_session_state_script" ]]; then
return 0
fi
if ! command -v "$NODE_BIN" >/dev/null 2>&1; then
return 0
fi

"$NODE_BIN" "$active_session_state_script" "$action" "$@" >/dev/null 2>&1 || true
}

record_active_session_state() {
local wt="$1"
local branch="$2"

run_active_session_state \
start \
--repo "$repo_root" \
--branch "$branch" \
--task "$TASK_NAME" \
--agent "$AGENT_NAME" \
--worktree "$wt" \
--pid "$$" \
--cli "$CODEX_BIN"
}

clear_active_session_state() {
local branch="$1"
run_active_session_state stop --repo "$repo_root" --branch "$branch"
}

origin_remote_supports_pr_finish() {
local origin_url
origin_url="$(git -C "$repo_root" remote get-url origin 2>/dev/null || true)"
Expand Down Expand Up @@ -833,6 +869,19 @@ if ! ensure_openspec_plan_workspace "$worktree_path" "$worktree_branch"; then
exit 1
fi

active_session_recorded=0
cleanup_active_session_state_on_exit() {
set +e
if [[ "${active_session_recorded:-0}" -eq 1 && -n "${worktree_branch:-}" && "${worktree_branch:-}" != "HEAD" ]]; then
clear_active_session_state "$worktree_branch"
active_session_recorded=0
fi
}

record_active_session_state "$worktree_path" "$worktree_branch"
active_session_recorded=1
trap cleanup_active_session_state_on_exit EXIT INT TERM

echo "[codex-agent] Launching ${CODEX_BIN} in sandbox: $worktree_path"
cd "$worktree_path"
set +e
Expand All @@ -841,6 +890,8 @@ codex_exit="$?"
set -e

cd "$repo_root"
cleanup_active_session_state_on_exit
trap - EXIT INT TERM
final_exit="$codex_exit"
auto_finish_completed=0

Expand Down
8 changes: 4 additions & 4 deletions scripts/openspec/init-change-workspace.sh
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ Describe the change in a sentence or two. Commit message is the spec of record.
- [ ] Confirm sandbox worktree is gone (\`git worktree list\`, \`git branch -a\`).
NOTESEOF
fi
echo "[guardex] OpenSpec change workspace (minimal) ready: ${CHANGE_DIR}"
echo "[guardex] Notes-only scaffold: ${CHANGE_DIR}/notes.md"
echo "[gitguardex] OpenSpec change workspace (minimal) ready: ${CHANGE_DIR}"
echo "[gitguardex] Notes-only scaffold: ${CHANGE_DIR}/notes.md"
exit 0
fi

Expand Down Expand Up @@ -129,5 +129,5 @@ The system SHALL enforce ${CAPABILITY_SLUG} behavior as defined by this change.
SPECEOF
fi

echo "[guardex] OpenSpec change workspace ready: ${CHANGE_DIR}"
echo "[guardex] OpenSpec change spec scaffold: ${SPEC_DIR}/spec.md"
echo "[gitguardex] OpenSpec change workspace ready: ${CHANGE_DIR}"
echo "[gitguardex] OpenSpec change spec scaffold: ${SPEC_DIR}/spec.md"
2 changes: 1 addition & 1 deletion test/install.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1339,7 +1339,7 @@ exit 1
assert.doesNotMatch(ghCalls, /pr merge .* --auto/);
const combinedOutput = `${result.stdout}\n${result.stderr}`;
assert.match(combinedOutput, /PR closed without merge; cannot continue auto-finish/);
assert.match(combinedOutput, /\[guardex\] Auto-finish flow failed for sandbox branch/);
assert.match(combinedOutput, /\[gitguardex\] Auto-finish flow failed for sandbox branch/);
assert.doesNotMatch(combinedOutput, /Auto-finish flow completed for sandbox branch/);
});

Expand Down