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
14 changes: 12 additions & 2 deletions .agents/skills/launch-openshell-gator/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,12 @@ For gator's PR/issue validation policy, load `gator-gate` inside the launched sa
| Path | Purpose |
|---|---|
| `scripts/agents/run.sh` | Manifest-driven OpenShell agent launcher. |
| `scripts/agents/gator/agent.yaml` | Gator manifest: default gateway, harness, providers, runtime, skills, and subagents. |
| `scripts/agents/gator/agent.yaml` | Gator manifest: immutable payload version, default gateway, harness, providers, runtime, skills, and subagents. |
| `scripts/agents/gator/Dockerfile` | Gator sandbox image source. Local launches build this image through OpenShell. |
| `scripts/agents/gator/policy.yaml` | Sandbox policy for the gator agent. |
| `scripts/agents/gator/bin/gh` | Gator-specific `gh` wrapper and same-SHA duplicate-post guard. |
| `scripts/agents/gator/bin/review-feedback-ledger` | Builds tree-aware review scope, durable findings, convergence telemetry, and checkpoint state. |
| `scripts/agents/gator/bin/validate-review-findings` | Enforces the blocker evidence schema and downgrades unsupported hypotheses. |
| `scripts/agents/gator/prompts/gator.md` | Rendered top-level prompt template baked into the payload. |
| `scripts/agents/gator/skills/gator-gate/SKILL.md` | In-sandbox gator state-machine skill. |
| `scripts/agents/gator/logs/` | Background launch and supervisor logs. |
Expand Down Expand Up @@ -283,6 +285,7 @@ Read that file directly. Important markers:
- `OpenAI Codex v...` plus `model: ...` confirms the Codex CLI and model actually used.
- `OPENSHELL_AGENT_RESULT {...}` is the bounded-cycle sentinel. In watch mode, the supervisor sleeps and relaunches after this line.
- `openshell-agent: still running watch cycle ...` is a heartbeat during long active model cycles.
- `review_feedback_lookup_failed` means Gator could not build the required cross-SHA feedback ledger and deliberately skipped a context-free review.

### Inspect Active Sandboxes

Expand All @@ -305,13 +308,20 @@ If `sandbox get` is not supported by the local CLI shape, use `openshell sandbox
| `status=waiting` | Normal watch wait. | Leave sandbox running. |
| `status=blocked` | Human/process blocker. | Read reason; decide whether a human action is needed. |
| `status=transient_failure` | Retryable infrastructure/auth/transport issue. | Let supervisor retry unless repeated failures hit the configured cap. |
| `status=terminal_failure` | Unrecoverable agent failure. | Inspect log and fix/relaunch. |
| `status=terminal_failure` | Unrecoverable or stale immutable payload. | Inspect the reason; rebuild/relaunch for `stale_gator_payload`. |
| `status=complete` | Target closed, merged, or one-shot complete. | Delete sandbox if no longer needed. |

## Restarting A Gator

Restart when the payload must change, the sandbox is wedged without a sentinel, the model/tooling version changed, or a transient failure repeats past the useful retry point.

Increment `payload_version` in `scripts/agents/gator/agent.yaml` whenever a
merged change alters the Gator prompt, gate skill, reviewer contract, write
guard, ledger, or bundled validator. Existing immutable watchers cannot replace
their own payload. New-version watchers detect later published versions and
stop with `stale_gator_payload`; relaunch every still-active older watcher after
the version bump is published.

Before deleting, check that the sandbox is truly stale or that the operator asked for a restart. If a bounded review cycle is actively running and still producing useful output, prefer leaving it alone.

```bash
Expand Down
84 changes: 81 additions & 3 deletions .claude/agents/principal-engineer-reviewer.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,63 @@ When reviewing code or diffs:
4. Call out issues by severity:
- **Critical** — Must fix before merge. Correctness bugs, security flaws,
data loss risks.
- **Warning** — Should fix. Error handling gaps, unclear contracts, missing
edge cases.
- **Suggestion** — Consider improving. Style, naming, minor simplifications.
- **Warning** — Must fix before merge when the change introduces or
materially worsens a concrete, reachable correctness, security, or
maintainability problem.
- **Suggestion** — Non-blocking improvement. Never require another revision
solely for a suggestion.
5. Reference specific files and line numbers (`file_path:line_number`).
6. When suggesting a change, show the concrete fix — don't just describe it.
7. If something is good, say so briefly. Positive signal is useful too.
8. When behavior, commands, or development workflows change, consult the `sync-agent-infra` maintenance map and verify that related skills were updated. Apply its full consistency checklist when the changes add, remove, or rename skills or crates; change workflow relationships or skill coverage; modify issue or PR templates; or change agent cross-references. Report missing companion updates or drift as a warning.
9. When the task includes a prior review feedback ledger, treat trusted resolved
or explicitly waived findings as durable across later revisions. Do not
re-raise the same finding with different wording unless the new diff
materially invalidates the prior rationale or reintroduces the defect. If
it does, identify the new evidence and explain why the earlier disposition
no longer applies.

### Pragmatic review calibration

- Review against the pull request's stated intent, supported user paths,
documented threat model, and established repository invariants.
- Make a finding blocking only when the scenario is concretely reachable, the
impact is material, the pull request introduces or materially worsens it, and
the proposed fix is proportionate to the risk.
- For every blocker, state reachability, impact, and why the pull request owns
the problem.
- Do not block on pre-existing or orthogonal defects, unsupported
configurations, speculative future requirements, stylistic preference, or
implausible failure combinations outside an adversarial trust boundary.
Mention valuable follow-up hardening as non-blocking.
- Account for implementation cost. Do not demand branching, abstraction,
configuration, or defensive machinery that makes the code harder to read and
maintain than the risk warrants.
- Treat attacker-controlled input at a real trust boundary as reachable even
when an honest user would not supply it. Pragmatism does not weaken
default-deny behavior or excuse concrete security regressions.
- On an initial review, inspect the complete change and report the complete
known blocker set. Group related examples under one root-cause invariant.
- On a follow-up review, carry existing obligations without duplicating them,
verify prior fixes, and review only the delta since the previous reviewed
head. Do not mine unchanged code for new findings.
- Raise a new unchanged-code blocker only when newly available evidence
demonstrates a Critical security, data-loss, or correctness defect. Explain
the evidence and why the initial review could not reasonably identify it.
- Treat pre-existing security issues as private security follow-up, not public
blockers on the current pull request. Treat other pre-existing defects as
non-blocking follow-up work.
- Keep docs, skill drift, diagnostic wording, and test-strength feedback
advisory unless the published contract is materially false, the diagnostic
creates an operational or safety failure, or missing coverage leaves a
concrete regression introduced by the change undetectable.
- If remediation expands into a new subsystem, crosses an explicit non-goal,
or creates new public configuration or policy, stop and request a maintainer
scope decision instead of extending the autonomous review.
- For a security-sensitive state machine, evaluate the applicable matrix of
protocol adapters, identity replacement, revocation timing, snapshot versus
live state, fallback behavior, and trust-boundary transitions. Group failures
under the governing invariant instead of reporting one matrix cell per pass.

When reviewing plans or architecture documents:

Expand Down Expand Up @@ -100,12 +150,40 @@ Structure your review clearly:

Omit empty sections. Keep it concise — density over length.

For each Critical or Warning finding, include:

- The stable finding ID when the task supplies an ID format
- The concrete reachable scenario
- The attacker or operator prerequisite
- The supported entry point and effectful sink
- The changed location that introduces or worsens the exposure
- The base behavior compared with head behavior
- The material impact
- Why the current change owns or worsens the problem
- A minimal deterministic test or constrained reproducer
- A proportionate requested fix

Keep Suggestions explicitly non-blocking. On follow-up reviews, do not repeat
Suggestions from an earlier review.

When the task supplies the Gator review findings contract, return only its JSON
envelope. Populate every evidence field from the supplied code and diff. Do not
invent missing evidence: leave the field absent so the validator downgrades the
proposal to a hypothesis. In `human_checkpoint` mode, return only Critical
defects introduced by the latest author delta.

## Security analysis

Apply this protocol when reviewing changes that touch security-sensitive areas:
sandbox runtime, policy engine, network egress, authentication, credential
handling, or any path that processes untrusted input (including LLM output).

Apply the pragmatic calibration above to security findings too. A real
attacker-controlled boundary makes an adversarial input reachable, but
pre-existing or orthogonal hardening does not become blocking merely because it
can be assigned a CWE. Explain how the current change introduces or materially
worsens the exposure.

1. **Threat modeling** — Map the data flow for the change. Where does untrusted
input (from an LLM, user, or network) enter? Where does it exit (to a
shell, filesystem, network, or database)? Identify trust boundaries that
Expand Down
5 changes: 4 additions & 1 deletion scripts/agents/gator/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,12 @@ ENV PATH="/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin"
RUN mkdir -p /etc/openshell
COPY policy.yaml /etc/openshell/policy.yaml
COPY bin/gh /usr/local/bin/gh-gator
COPY bin/review-feedback-ledger /usr/local/bin/review-feedback-ledger
COPY bin/validate-review-findings /usr/local/bin/validate-review-findings
RUN rm -f /usr/local/bin/gh && \
cp /usr/local/bin/gh-gator /usr/local/bin/gh && \
chmod 755 /usr/local/bin/gh
chmod 755 /usr/local/bin/gh /usr/local/bin/review-feedback-ledger \
/usr/local/bin/validate-review-findings

RUN printf 'export PATH="/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin"\nexport PS1="\\u@\\h:\\w\\$ "\n' \
> /sandbox/.bashrc && \
Expand Down
14 changes: 12 additions & 2 deletions scripts/agents/gator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Use `--harness codex` to select Codex explicitly. Other harness names are reject

Use `--codex-bin "$(command -v codex)"` only when the host executable is compatible with the sandbox OS and architecture.

The manifest-driven launcher at `scripts/agents/run.sh` reads `agent.yaml`, which defines the agent prompt template, provider profile IDs, provider credential sources, gateway settings, skills, subagents, sandbox defaults, runtime mode, and harness defaults. The shared sandbox entrypoint at `scripts/agents/runtime/entrypoint.sh` starts the in-sandbox supervisor, which invokes the selected harness adapter for bounded cycles.
The manifest-driven launcher at `scripts/agents/run.sh` reads `agent.yaml`, which defines the versioned immutable payload, prompt template, provider profile IDs, provider credential sources, gateway settings, skills, subagents, supporting resources, sandbox defaults, runtime mode, and harness defaults. The shared sandbox entrypoint at `scripts/agents/runtime/entrypoint.sh` starts the in-sandbox supervisor, which invokes the selected harness adapter for bounded cycles.

The launcher:

Expand All @@ -36,16 +36,26 @@ The launcher:
- For `--harness codex`, configures gateway-managed refresh for `CODEX_AUTH_ACCESS_TOKEN` and rotates it before launching the sandbox.
- Enables `providers_v2_enabled`, `agent_policy_proposals_enabled`, and `proposal_approval_mode=auto` at gateway scope.
- Uses the gator image policy copied to `/etc/openshell/policy.yaml`.
- Installs the gator-specific `gh` wrapper from `gator/bin/gh` as `/usr/local/bin/gh` to prevent duplicate same-head-SHA gator dispositions.
- Installs the gator-specific `gh` wrapper from `gator/bin/gh` as `/usr/local/bin/gh` to fail closed when same-head-SHA history cannot be checked, prevent duplicate dispositions, and require versioned review payloads.
- Installs `gator/bin/review-feedback-ledger` as `/usr/local/bin/review-feedback-ledger` so reviews receive tree- and patch-aware scope, prior summaries and findings, resolution state, convergence telemetry, and the three-round human checkpoint.
- Installs `gator/bin/validate-review-findings` to downgrade blockers that lack the required reachability, ownership, base-vs-head, impact, and reproducer evidence.
- Bakes `scripts/agents/gator/skills/gator-gate/SKILL.md` into `/etc/openshell/agent-payload`.
- Bakes `.claude/agents/principal-engineer-reviewer.md` so the selected harness can run a deterministic independent reviewer execution through `/etc/openshell/agent-payload/runtime/subagent.sh principal-engineer-reviewer < task.md`.
- For `--harness codex`, optionally bakes a host Codex executable as `/etc/openshell/agent-payload/runtime/harnesses/codex/codex`.
- Starts the selected harness without a TTY.
- Runs gator in `watch` mode by default. The sandbox stays alive while the supervisor sleeps between bounded Codex cycles, so Codex is not connected during passive PR waits. The supervisor prints periodic heartbeat lines during active cycles and passive sleeps.
- Makes each watch cycle compare its immutable payload version with the version published on the default branch. A stale watcher stops without GitHub writes and must be relaunched.
The GitHub provider profile allows read-only GraphQL queries on `api.github.com/graphql` so `gh` read paths can use GraphQL when needed. Write operations remain REST-only and scoped to the two allowed repositories.

Set `GATOR_CODEX_ACCESS_CREDENTIAL_KEY` or pass `--codex-access-key` if the gator Codex profile uses a credential key other than `CODEX_AUTH_ACCESS_TOKEN` for the short-lived access token.

Use `--once` for a single reconciliation cycle. Use `--poll-interval <seconds>` to change the default 15-minute watch cadence.

The launcher preserves existing gateway-owned Codex refresh material by default so multiple gator sandboxes do not overwrite each other's refresh-token lineage from host Codex auth. If gateway rotation fails, the launcher automatically resets gateway refresh material from host Codex auth and retries once. After `codex logout && codex login`, you can also pass `--reset-refresh` to force that reset before rotation.

## Tests

```shell
bash scripts/agents/gator/bin/gh_guard_test.sh
bash scripts/agents/gator/bin/review_feedback_ledger_test.sh
```
6 changes: 6 additions & 0 deletions scripts/agents/gator/agent.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# SPDX-License-Identifier: Apache-2.0

id: gator
payload_version: 2
display_name: Gator Gate Agent
description: Validate and monitor OpenShell GitHub issues and pull requests through the gator state machine.

Expand Down Expand Up @@ -82,6 +83,11 @@ skills:
source: agent://skills/gator-gate/SKILL.md
destination: skills/gator-gate/SKILL.md

resources:
- id: gator-review-findings-schema
source: agent://skills/gator-gate/references/review-findings-schema.md
destination: skills/gator-gate/references/review-findings-schema.md

subagents:
- id: principal-engineer-reviewer
source: repo://.claude/agents/principal-engineer-reviewer.md
Expand Down
32 changes: 28 additions & 4 deletions scripts/agents/gator/bin/gh
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ set -euo pipefail

REAL_GH="${OPENSHELL_REAL_GH:-/usr/bin/gh}"
GATOR_MARKER='> **gator-agent**'
GATOR_PAYLOAD_VERSION="${OPENSHELL_AGENT_PAYLOAD_VERSION:-2}"

if [[ $# -lt 1 || "$1" != "api" ]]; then
exec "$REAL_GH" "$@"
Expand Down Expand Up @@ -135,10 +136,16 @@ guard_duplicate_gator_disposition() {
[[ "$body" != *"## Monitoring Complete"* ]] || return 0

local pull_json head_sha current_is_draft
pull_json="$($REAL_GH api "repos/$owner/$repo/pulls/$number" 2>/dev/null || true)"
if ! pull_json="$($REAL_GH api "repos/$owner/$repo/pulls/$number" 2>/dev/null)"; then
echo "openshell-agent: blocked gator write because current PR head lookup failed for $owner/$repo#$number" >&2
return 21
fi
head_sha="$(printf '%s' "$pull_json" | jq -r '.head.sha // empty' 2>/dev/null || true)"
current_is_draft="$(printf '%s' "$pull_json" | jq -r '.draft // false' 2>/dev/null || true)"
[[ -n "$head_sha" ]] || return 0
if [[ -z "$head_sha" ]]; then
echo "openshell-agent: blocked gator write because current PR head was missing for $owner/$repo#$number" >&2
return 21
fi

if is_legacy_reviewer_failure_disposition "$body" "$head_sha"; then
echo "openshell-agent: blocked public reviewer sub-agent failure disposition for $owner/$repo#$number ($head_sha)" >&2
Expand All @@ -147,14 +154,31 @@ guard_duplicate_gator_disposition() {
fi

local existing_comments existing_reviews
existing_comments="$($REAL_GH api "repos/$owner/$repo/issues/$number/comments" --paginate --jq '.[] | select(.body | contains("> **gator-agent**")) | .body | @json' 2>/dev/null || true)"
existing_reviews="$($REAL_GH api "repos/$owner/$repo/pulls/$number/reviews" --paginate --jq '.[] | select(.body | contains("> **gator-agent**")) | .body | @json' 2>/dev/null || true)"
if ! existing_comments="$($REAL_GH api "repos/$owner/$repo/issues/$number/comments" --paginate --jq '.[] | select(.body | contains("> **gator-agent**")) | .body | @json' 2>/dev/null)"; then
echo "openshell-agent: blocked gator write because existing comment lookup failed for $owner/$repo#$number" >&2
return 21
fi
if ! existing_reviews="$($REAL_GH api "repos/$owner/$repo/pulls/$number/reviews" --paginate --jq '.[] | select(.body | contains("> **gator-agent**")) | .body | @json' 2>/dev/null)"; then
echo "openshell-agent: blocked gator write because existing review lookup failed for $owner/$repo#$number" >&2
return 21
fi

if has_blocking_same_sha_disposition "$head_sha" "$current_is_draft" "$(printf '%s\n%s\n' "$existing_comments" "$existing_reviews")"; then
echo "openshell-agent: blocked duplicate gator same-SHA disposition for $owner/$repo#$number ($head_sha)" >&2
echo "openshell-agent: push a new commit, remove the old disposition, or set OPENSHELL_GATOR_ALLOW_SAME_SHA_COMMENT=1 for an explicit maintainer-requested same-SHA action" >&2
return 20
fi

if [[ "$body" == *"## PR Review Status"* || "$body" == *"## Re-check After"* ]]; then
if [[ "$body" != *"Head SHA: \`$head_sha\`"* && "$body" != *"Head SHA: $head_sha"* ]]; then
echo "openshell-agent: blocked gator review disposition without the exact current Head SHA for $owner/$repo#$number" >&2
return 22
fi
if [[ "$body" != *"Gator payload: \`$GATOR_PAYLOAD_VERSION\`"* && "$body" != *"Gator payload: $GATOR_PAYLOAD_VERSION"* ]]; then
echo "openshell-agent: blocked gator review disposition without Gator payload version $GATOR_PAYLOAD_VERSION" >&2
return 22
fi
fi
}

if [[ "${OPENSHELL_GATOR_ALLOW_SAME_SHA_COMMENT:-}" != "1" && "${method^^}" == "POST" ]]; then
Expand Down
Loading
Loading