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 .egg/schemas/checkpoint.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@
},
"repo": {
"type": ["string", "null"],
"description": "Source repository in owner/repo format (e.g. 'jwbron/egg')",
"description": "Source repository in owner/repo format (e.g. 'owner/repo')",
"pattern": "^[a-zA-Z0-9._-]+/[a-zA-Z0-9._-]+$",
"default": null
},
Expand Down
22 changes: 15 additions & 7 deletions .github/workflows/on-review-feedback.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,9 @@ on:
type: string
default: "jwbron/egg/action@main"
authorized_users:
description: 'Comma-separated list of GitHub usernames authorized to trigger the bot (via review or @mention)'
required: false
description: 'Comma-separated list of GitHub usernames authorized to trigger the bot (via review or @mention). Required — there is no default.'
required: true
type: string
default: "jwbron"
reviewer_username:
description: 'GitHub username of the reviewer bot (for review trigger detection)'
required: false
Expand Down Expand Up @@ -88,9 +87,18 @@ jobs:
steps:
- name: Validate required repository variables
run: |
missing=()
if [[ -z "${{ vars.EGG_BOT_USERNAME }}" ]]; then
echo "::error::Required repository variable 'EGG_BOT_USERNAME' is not set"
echo "::error::Set it in Settings > Secrets and variables > Actions > Variables"
missing+=("EGG_BOT_USERNAME")
fi
if [[ -z "${{ vars.EGG_AUTHORIZED_USERS }}" ]]; then
missing+=("EGG_AUTHORIZED_USERS")
fi
if (( ${#missing[@]} > 0 )); then
for var in "${missing[@]}"; do
echo "::error::Required repository variable '$var' is not set"
done
echo "::error::Set them in Settings > Secrets and variables > Actions > Variables"
exit 1
fi
echo "All required repository variables are configured"
Expand Down Expand Up @@ -120,12 +128,12 @@ jobs:
echo "bot_username=${{ inputs.bot_username }}"
echo "branch_prefix=${{ inputs.branch_prefix }}"
echo "reviewer_username=${{ inputs.reviewer_username || '' }}"
echo "authorized_users=${{ inputs.authorized_users || 'jwbron' }}"
echo "authorized_users=${{ inputs.authorized_users }}"
else
echo "bot_username=${{ vars.EGG_BOT_USERNAME }}"
echo "branch_prefix=${{ vars.EGG_BRANCH_PREFIX }}"
echo "reviewer_username=${{ vars.EGG_REVIEWER_USERNAME || '' }}"
echo "authorized_users=${{ vars.EGG_AUTHORIZED_USERS || 'jwbron' }}"
echo "authorized_users=${{ vars.EGG_AUTHORIZED_USERS }}"
fi
echo "max_feedback_rounds=${{ inputs.max_feedback_rounds || '5' }}"

Expand Down
10 changes: 10 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -391,8 +391,18 @@ k3s-secrets: ## Create gateway secrets from ~/.config/egg/

deploy: k3s-secrets ## Deploy egg to k3s
@echo "Deploying to k3s with tag $(EGG_IMAGE_TAG)..."
@command -v envsubst >/dev/null 2>&1 || { \
echo "ERROR: envsubst not found. Install GNU gettext: 'dnf install gettext' or 'brew install gettext'." >&2; \
exit 1; \
}
export KUBECONFIG=$${KUBECONFIG:-/etc/rancher/k3s/k3s.yaml} && \
export EGG_HOST_HOME="$${EGG_HOST_HOME:-$$HOME}" && \
export EGG_HOST_REPO_MAP="$${EGG_HOST_REPO_MAP:-$$(scripts/build-host-repo-map.py)}" && \
echo " EGG_HOST_HOME=$$EGG_HOST_HOME" && \
echo " EGG_HOST_REPO_MAP=$$EGG_HOST_REPO_MAP" && \
kubectl kustomize k8s/overlays/local/ | \
envsubst '$$EGG_HOST_HOME $$EGG_HOST_REPO_MAP' | \
sed -E "/name: EGG_HOST_REPO_MAP$$/{N;s|^(\s*- name: EGG_HOST_REPO_MAP\s*\n\s*value: )(\{.*\})$$|\1'\2'|}" | \
sed -e "s|egg-orchestrator:latest|egg-orchestrator:$(EGG_IMAGE_TAG)|g" \
-e "s|egg-gateway:latest|egg-gateway:$(EGG_IMAGE_TAG)|g" \
-e "s|egg-sandbox:latest|egg-sandbox:$(EGG_IMAGE_TAG)|g" | \
Expand Down
2 changes: 1 addition & 1 deletion action/generate-config.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
# - launcher-secret (auth token for launcher API calls)
#
# Required environment variables:
# GITHUB_REPOSITORY — owner/repo (e.g., "jwbron/egg")
# GITHUB_REPOSITORY — owner/repo (e.g., "owner/repo")
# GITHUB_ACTOR — GitHub username triggering the workflow
# GITHUB_ACTOR_ID — Numeric ID for noreply email
# INPUT_ANTHROPIC_OAUTH_TOKEN — Anthropic OAuth token
Expand Down
2 changes: 1 addition & 1 deletion config/repo_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,7 @@ def is_checkpoint_repo(owner: str, repo: str) -> bool:
"""Check if a repository is configured as a checkpoint destination.

Args:
owner: Repository owner (e.g. "jwbron")
owner: Repository owner (e.g. "my-org")
repo: Repository name (e.g. "egg-checkpoints")

Returns:
Expand Down
2 changes: 1 addition & 1 deletion config/secrets.template.env
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ GATEWAY_BOT_BRANCH_PREFIX=""

# Trusted GitHub usernames whose branches the bot can push to (optional)
# Comma-separated list of usernames (case-insensitive)
# Example: GATEWAY_TRUSTED_USERS="jwbron,octocat"
# Example: GATEWAY_TRUSTED_USERS="alice,bob"
GATEWAY_TRUSTED_USERS=""

# =============================================================================
Expand Down
2 changes: 1 addition & 1 deletion docs/architecture/logging.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ All log entries include these fields:
"traceFlags": "01",
"context": {
"task_id": "bd-xyz789",
"repository": "jwbron/egg",
"repository": "owner/repo",
"pr_number": 123
}
}
Expand Down
6 changes: 3 additions & 3 deletions docs/architecture/orchestrator.md
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ During the `implement` phase, certain `.egg-state/` subdirectories are mounted r

The orchestrator calls `ensure_egg_state_dirs()` before spawning containers to create the required directories (bind mounts require existing source paths) and place `.egg-readonly` marker files explaining the restriction and current phase. Reviewer agents do not receive the `.egg-readonly` marker in the `reviews/` directory. Then `phase_readonly_mounts()` generates the readonly `MountSpec` entries, which are added alongside the existing `.git` shadow mounts. Only directories that exist on the host are mounted (missing directories are skipped). See `shared/egg_container/__init__.py` and `orchestrator/container_spawner.py`.

**Host path translation:** The gateway returns worktree paths relative to the host (e.g., `/home/jwies/.egg-worktrees/...`), but the orchestrator pod only sees these via `/home/egg/...` hostPath mounts. The spawner uses the `HOST_HOME` env var to translate host paths to orchestrator-accessible local paths for `is_dir()` checks and `ensure_egg_state_dirs()`. hostPath mount sources still use the original host paths unchanged.
**Host path translation:** The gateway returns worktree paths relative to the host (e.g., `/home/user/.egg-worktrees/...`), but the orchestrator pod only sees these via `/home/egg/...` hostPath mounts. The spawner uses the `HOST_HOME` env var to translate host paths to orchestrator-accessible local paths for `is_dir()` checks and `ensure_egg_state_dirs()`. hostPath mount sources still use the original host paths unchanged.

**Worktree state synchronization:** The orchestrator maintains bidirectional synchronization between local worktree branches and their remote counterparts:

Expand Down Expand Up @@ -470,7 +470,7 @@ The `wait_for_status_change` tool is the event-triggered sibling of `get_status`

Available MCP tools (gateway-backed, requires `gateway_url`): `list_checkpoints`, `search_checkpoints`, `get_contract`

The gateway-backed checkpoint tools (`list_checkpoints`, `search_checkpoints`) accept an optional `repo` parameter to specify the checkpoint repository in `owner/repo` format (e.g., `jwbron/egg-checkpoints`). When provided, this is forwarded as the `source_repo` query parameter to the gateway checkpoint endpoint. The `get_contract` tool also uses the gateway session but does not require the `repo` parameter.
The gateway-backed checkpoint tools (`list_checkpoints`, `search_checkpoints`) accept an optional `repo` parameter to specify the checkpoint repository in `owner/repo` format (e.g., `owner/repo-checkpoints`). When provided, this is forwarded as the `source_repo` query parameter to the gateway checkpoint endpoint. The `get_contract` tool also uses the gateway session but does not require the `repo` parameter.

**CLI Access:**
The `egg-orch` CLI (`sandbox/bin/egg-orch`) provides command-line access to all orchestrator API endpoints. Available in sandbox containers for agent use, or can be run from the host with appropriate environment variables. See the [README CLI Reference](../../README.md#egg-orch-cli) for command details.
Expand Down Expand Up @@ -559,7 +559,7 @@ if is_orchestrator_mode():
| `EGG_AGENT_ROLE` | Agent role for multi-agent mode | None |
| `EGG_BRANCH` | Target branch for the agent's worktree | `egg/{pipeline_id}/work` |
| `EGG_PRIVATE_MODE` | Private network mode (set by host wrapper, detected by `egg-sdlc`) | None |
| `HOST_HOME` | Host machine's home directory (e.g., `/home/jwies`); used to translate host worktree paths to orchestrator-accessible paths | None |
| `HOST_HOME` | Host machine's home directory (e.g., `/home/user`); used to translate host worktree paths to orchestrator-accessible paths | None |

### Constants

Expand Down
2 changes: 1 addition & 1 deletion docs/architecture/sdlc-pipeline.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ The contract is a JSON document tracking the complete state of an issue through
"review_cycles": 1
}]
}],
"workflow_owner": "jwbron",
"workflow_owner": "my-org",
"audit_log": [...]
}
```
Expand Down
20 changes: 10 additions & 10 deletions docs/guides/checkpoint-access.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ Both `--repo-path` and `--checkpoint-repo` can be placed **before or after** the

```bash
# These are equivalent:
egg-checkpoint --checkpoint-repo jwbron/egg-checkpoints list --issue 42
egg-checkpoint list --checkpoint-repo jwbron/egg-checkpoints --issue 42
egg-checkpoint --checkpoint-repo owner/repo-checkpoints list --issue 42
egg-checkpoint list --checkpoint-repo owner/repo-checkpoints --issue 42
```

If the flag is supplied in both positions, the last value wins.
Expand Down Expand Up @@ -151,7 +151,7 @@ All list/context filters use AND logic (all must match). Filters available:
| Issue | `--issue N` | `--issue 530` |
| PR | `--pr N` | `--pr 42` |
| Pipeline | `--pipeline ID` | `--pipeline issue-530` |
| Repo | `--repo OWNER/REPO` | `--repo jwbron/egg` |
| Repo | `--repo OWNER/REPO` | `--repo owner/repo` |
| Session | `--session ID` | `--session container-abc` |
| Branch | `--branch NAME` | `--branch egg/feature` |
| Trigger | `--trigger TYPE` | `--trigger commit` or `--trigger session_end` |
Expand Down Expand Up @@ -184,7 +184,7 @@ Supported composite role names: `reviewer_code`, `reviewer_contract`, `reviewer_
When a query matches no checkpoints, the CLI now prints the repository and branch it searched to stderr:

```
Searched jwbron/egg branch egg/checkpoints/v2
Searched owner/repo branch egg/checkpoints/v2
No checkpoints found matching filters
```

Expand Down Expand Up @@ -269,7 +269,7 @@ egg-checkpoint cost --issue $EGG_ISSUE_NUMBER

### "No checkpoints found"

The CLI now shows which repository and branch it searched when no results are found (e.g., `Searched jwbron/egg branch egg/checkpoints/v2`). Check the displayed repo/branch — if it's unexpected:
The CLI now shows which repository and branch it searched when no results are found (e.g., `Searched owner/repo branch egg/checkpoints/v2`). Check the displayed repo/branch — if it's unexpected:

1. **Checkpoints in a separate repo**: Some projects store checkpoints in a dedicated repo (e.g., `owner/project-checkpoints`). Set the `EGG_CHECKPOINT_REPO` env var or use `--checkpoint-repo`.
2. **Missing `repositories.yaml`**: Auto-detection relies on a config file that may not exist in the sandbox. Set the env var instead.
Expand Down Expand Up @@ -314,7 +314,7 @@ List checkpoints with optional filters.
```
list_checkpoints(issue=1489, phase="implement")
list_checkpoints(pipeline="issue-1489", agent_type="coder")
list_checkpoints(issue=1489, repo="jwbron/egg-checkpoints")
list_checkpoints(issue=1489, repo="owner/repo-checkpoints")
```

**Parameters:** `issue` (int), `pipeline` (string), `agent_type` (string), `phase` (string), `status` (string), `repo` (string, `owner/repo` format), `limit` (int, default 20)
Expand All @@ -325,18 +325,18 @@ Search checkpoint metadata for matching text (searches agent_type, pipeline_phas

```
search_checkpoints(text="coder", pipeline="issue-1489")
search_checkpoints(text="reviewer", repo="jwbron/egg-checkpoints")
search_checkpoints(text="reviewer", repo="owner/repo-checkpoints")
```

**Parameters:** `text` (string, required), `issue` (int), `pipeline` (string), `agent_type` (string), `repo` (string, `owner/repo` format), `limit` (int, default 10)

### Specifying the checkpoint repository

When checkpoints are stored in a separate repository (e.g., `jwbron/egg-checkpoints`), use the `repo` parameter to target it:
When checkpoints are stored in a separate repository (e.g., `owner/repo-checkpoints`), use the `repo` parameter to target it:

```
list_checkpoints(issue=1489, repo="jwbron/egg-checkpoints")
search_checkpoints(text="error", repo="jwbron/egg-checkpoints")
list_checkpoints(issue=1489, repo="owner/repo-checkpoints")
search_checkpoints(text="error", repo="owner/repo-checkpoints")
```

The `repo` value is forwarded as `source_repo` to the gateway checkpoint endpoint.
Expand Down
16 changes: 8 additions & 8 deletions docs/guides/custom-phase.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ a local `kubectl port-forward`):
run_agent_task(
phase = "refine",
roles = ["refiner"],
repo = "jwbron/egg",
repo = "owner/repo",
description = "Investigate how concurrent_executor filters the review graph"
)
```
Expand All @@ -83,7 +83,7 @@ Minimal form — default roster, no branch, no PR, no upstream contract:
```
run_agent_task(
phase = "implement",
repo = "jwbron/egg",
repo = "owner/repo",
description = "Fix typo in README.md under ## Quickstart"
)
```
Expand Down Expand Up @@ -250,7 +250,7 @@ would be."
run_agent_task(
phase = "refine",
roles = ["refiner"],
repo = "jwbron/egg",
repo = "owner/repo",
description = "Evaluate cost of migrating integration tests off compose"
)
```
Expand All @@ -271,7 +271,7 @@ overkill (no tester needed, no documenter needed):
run_agent_task(
phase = "implement",
roles = ["coder"],
repo = "jwbron/egg",
repo = "owner/repo",
description = "Fix log-level typo in orchestrator/routes/pipelines.py line 42"
)
```
Expand All @@ -289,7 +289,7 @@ documenter churn:
run_agent_task(
phase = "implement",
roles = ["coder", "reviewer_code"],
repo = "jwbron/egg",
repo = "owner/repo",
description = "Refactor _handle_submit_task to share a common validator helper with _handle_babysit_pr"
)
```
Expand All @@ -305,12 +305,12 @@ branches. This is the **subsumption path** (decision-2): the underlying
run_agent_task(
phase = "implement",
pr_number = 1234,
repo = "jwbron/egg",
repo = "owner/repo",
description = "Improve test coverage on the PR's new validator helper"
)
```

This is equivalent to `babysit_pr(pr_number=1234, repo="jwbron/egg")`
This is equivalent to `babysit_pr(pr_number=1234, repo="owner/repo")`
end-to-end — use `babysit_pr` for the canonical PR-improvement flow,
and `run_agent_task` when you want a non-default roster on a PR.

Expand All @@ -323,7 +323,7 @@ do):
```
run_agent_task(
phase = "plan",
repo = "jwbron/egg",
repo = "owner/repo",
description = "Plan the refactor of _run_concurrent_phase",
analysis = "<markdown body of the analysis>"
)
Expand Down
13 changes: 4 additions & 9 deletions docs/guides/github-automation.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ Without it, the system falls back to posting reviews as comments (self-review mo
1. **Trigger authorization** — For event-triggered runs, verifies the triggering user is authorized:
- Bot reviews always trigger (the bot can review its own PRs)
- Human reviews and @mentions require the user to be in the `authorized_users` list
- Configured via `EGG_AUTHORIZED_USERS` repository variable (defaults to `jwbron`)
- Configured via the `EGG_AUTHORIZED_USERS` repository variable (required — the workflow fails fast if the variable is unset, so there is no implicit default)
- Manual/workflow_call triggers bypass authorization

2. **Filter checks** — Only runs when:
Expand Down Expand Up @@ -593,16 +593,11 @@ Event-triggered workflows require these repository variables (Settings → Secre
|----------|---------|---------|
| `EGG_BOT_USERNAME` | Bot's GitHub username for self-trigger prevention | `james-in-a-box[bot]` |
| `EGG_BRANCH_PREFIX` | Branch prefix for bot-owned branches | `egg` |
| `EGG_AUTHORIZED_USERS` | Comma-separated list of GitHub users authorized to trigger review feedback via reviews or @mentions | `alice,bob` |

Reusable workflows called via `workflow_call` receive these values as inputs from the caller instead.

### Optional Repository Variables
`EGG_AUTHORIZED_USERS` controls who can trigger the Address Review Feedback workflow through human reviews or @mentions — the bot itself is always authorized to trigger via automated reviews. The workflow fails fast at the validation step if any required variable is unset, so there is no implicit default.

| Variable | Purpose | Default |
|----------|---------|---------|
| `EGG_AUTHORIZED_USERS` | Comma-separated list of GitHub users authorized to trigger review feedback via reviews or @mentions | `jwbron` |

This variable controls who can trigger the Address Review Feedback workflow through human reviews or @mentions. The bot itself is always authorized to trigger via automated reviews.
Reusable workflows called via `workflow_call` receive these values as inputs from the caller instead.

### Per-Repository Customization

Expand Down
12 changes: 3 additions & 9 deletions docs/guides/reusable-workflows.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ jobs:
| `bot_username` | GitHub username of your bot | Yes |
| `branch_prefix` | Prefix for bot-owned branches | Yes |
| `action_ref` | Reference to egg action (documentation only; see note) | No |
| `authorized_users` | Comma-separated list of authorized users | No (default: `jwbron`) |
| `authorized_users` | Comma-separated list of authorized users (review-feedback workflow only) | Yes (no default) |
| `timeout` | Timeout in minutes | No (varies by workflow) |

## Repository Variables
Expand All @@ -131,20 +131,14 @@ jobs:
|----------|---------|---------|
| `EGG_BOT_USERNAME` | Bot's GitHub username | `james-in-a-box[bot]` |
| `EGG_BRANCH_PREFIX` | Branch prefix for bot-owned branches | `egg` |

**OPTIONAL**: Additional variables for customization:

| Variable | Purpose | Default |
|----------|---------|---------|
| `EGG_AUTHORIZED_USERS` | Comma-separated list of users authorized to trigger review feedback | `jwbron` |
| `EGG_AUTHORIZED_USERS` | Comma-separated list of users authorized to trigger review feedback via reviews or @mentions | `alice,bob` |

### Setting Up Repository Variables

1. Go to your repository's **Settings** → **Secrets and variables** → **Actions**
2. Click the **Variables** tab
3. Click **New repository variable**
4. Add required variables (`EGG_BOT_USERNAME` and `EGG_BRANCH_PREFIX`)
5. Optionally add `EGG_AUTHORIZED_USERS` to control who can trigger feedback via reviews or @mentions
4. Add the required variables (`EGG_BOT_USERNAME`, `EGG_BRANCH_PREFIX`, `EGG_AUTHORIZED_USERS`)

**Note**: Workflows will fail with a validation error if required variables are not set.

Expand Down
2 changes: 1 addition & 1 deletion docs/guides/sdlc-pipeline.md
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,7 @@ The local orchestrator handles concurrent contract updates through `orchestrator
}
],
"decisions": [],
"workflow_owner": "jwbron",
"workflow_owner": "my-org",
"audit_log": []
}
```
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/agent-roles.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ All agents within a phase run concurrently via BRC consensus. Concurrency is ena

### `reviewer_agent_design`

**Scope**: Egg repo only (`jwbron/egg`). Not spawned for pipelines on other repos.
**Scope**: Egg repo only (`jwbron/egg`). Not spawned for pipelines on other repos. The canonical repo string is hardcoded in `shared/egg_contracts/agent_roles.py` (`EGG_REPO`).

**Purpose**: Review the analysis for agent-mode alignment and anti-patterns (e.g., correct use of egg's structural enforcement model).

Expand Down
Loading
Loading