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 action/build-agent-mode-design-review-prompt.sh
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ Flag these **clear** anti-patterns:
4. **Rigid procedures**: Micromanaging step-by-step procedures when objectives would suffice
5. **Prompt-level security**: Using instructions for constraints that should be sandbox-enforced
6. **Direct LLM API calls outside sandbox**: Calling the Anthropic API from orchestrator, gateway, or shared code instead of delegating to sandbox containers (enforced by EGG200 linter)
7. **Direct API calls bypassing Claude Code**: Using raw HTTP calls to the Anthropic API instead of claude --print (Claude Code headless mode). Unlike item 6 (scoped to infra code), this applies everywhere including sandbox code.
7. **Direct API calls bypassing the Agent SDK**: Using raw HTTP calls to the Anthropic API instead of run_agent() (in-sandbox) or build_agent_command() (orchestrator-spawned containers). Unlike item 6 (scoped to infra code), this applies everywhere including sandbox code.
8. **Hardcoded model identifiers**: Using full model IDs like claude-sonnet-4-20250514 instead of short aliases (sonnet, opus, haiku) (enforced by EGG201 linter)

## What to Skip
Expand Down
2 changes: 1 addition & 1 deletion docs/architecture/orchestrator.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ A two-tier health check framework provides structured, extensible failure detect

**Tier 1 (Programmatic)** checks are fast and deterministic. They run on every lifecycle trigger and cover structural invariants: container liveness, startup state, phase output presence, and state consistency. Container liveness and startup state checks are adapters over existing `ContainerMonitor` and `reconcile_stale_containers` logic. The phase output check detects the issue-835 pattern where agents complete successfully but produce no artifacts (e.g., no commits on the remote branch after an implement phase). The state consistency check cross-references orchestrator state against Docker reality and contract data.

**Tier 2 (Semantic)** checks are LLM-powered and evaluate whether agents made meaningful progress. The `AgentInspectorCheck` sends pipeline context (recent commits, diff stats, agent output files, SDLC contract state) to Claude via Claude Code headless mode (default model: `sonnet`) and interprets a structured JSON verdict. On API failure, the check gracefully degrades to HEALTHY — Tier 2 failures never block the pipeline. Tier 2 checks run conditionally — at `WAVE_COMPLETE` only when Tier 1 reports `DEGRADED`, and always at `PHASE_COMPLETE` and `ON_DEMAND`.
**Tier 2 (Semantic)** checks are LLM-powered and evaluate whether agents made meaningful progress. The `AgentInspectorCheck` sends pipeline context (recent commits, diff stats, agent output files, SDLC contract state) to Claude via the Agent SDK (default model: `sonnet`) and interprets a structured JSON verdict. On API failure, the check gracefully degrades to HEALTHY — Tier 2 failures never block the pipeline. Tier 2 checks run conditionally — at `WAVE_COMPLETE` only when Tier 1 reports `DEGRADED`, and always at `PHASE_COMPLETE` and `ON_DEMAND`.

**Lifecycle integration:**
- `STARTUP`: Runs after startup reconciliation on all RUNNING pipelines (non-blocking)
Expand Down
6 changes: 6 additions & 0 deletions docs/development/STRUCTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,12 @@ sandbox/

```
shared/
├── egg_agent/ # Claude Agent SDK wrapper (in-sandbox agent calls + command builder)
│ ├── __init__.py # Public API: AgentResult, build_agent_command
│ ├── __main__.py # CLI entry point (python3 -m egg_agent)
│ ├── client.py # run_agent(), run_agent_async() via claude-agent-sdk
│ ├── command.py # build_agent_command() for orchestrator-spawned containers
│ └── result.py # AgentResult dataclass
├── egg_config/ # Configuration utilities
│ ├── constants.py # Centralized constants (ports, networks, container names, devserver resource limits, infrastructure branch names)
│ ├── compose_config.py # Bridges config.yaml settings to docker-compose environment variables
Expand Down
11 changes: 8 additions & 3 deletions docs/guides/agent-mode-design.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,14 @@ If the agent decides something isn't worth commenting on, or needs a different a

These conventions extend the core principle ("the sandbox is the constraint") with enforced boundaries:

### Use Claude Code headless mode, not direct API calls
### Use the Agent SDK or Claude Code headless mode, not direct API calls

All LLM calls should go through `claude --print` (Claude Code headless mode), not through direct `httpx.post()` or Anthropic SDK calls. This ensures:
LLM calls must never use direct `httpx.post()` or Anthropic SDK calls. Two approaches are supported:

- **In-sandbox code** (e.g., `egg-health-inspect`, `sandbox/llm/`): use `egg_agent.client.run_agent()`, which wraps `claude-agent-sdk` for in-process execution.
- **Orchestrator/gateway code spawning containers**: use `egg_agent.build_agent_command()` to build the `claude --print` command passed to `spawn_agent_container()`.

Both approaches ensure:
- Consistent tool access across all agent invocations
- The agent can use tools (file reading, shell commands, GitHub CLI) rather than being limited to a single prompt/response
- Centralized configuration (model selection, permissions, timeouts)
Expand Down Expand Up @@ -332,7 +337,7 @@ When designing a new agent workflow, ask:
- [ ] Would this design work if the agent needs more context than I anticipated?
- [ ] Am I preserving useful existing functionality while removing unnecessary complexity?
- [ ] Am I calling the Anthropic API directly from orchestrator/gateway/shared code? (Delegate to sandbox)
- [ ] Am I using `httpx`/`requests` to call the API instead of `claude --print`?
- [ ] Am I using `httpx`/`requests` to call the API instead of `egg_agent.client.run_agent()` (in-sandbox) or `build_agent_command()` (orchestrator-spawned containers)?
- [ ] Am I using pinned model identifiers instead of aliases (`sonnet`, `opus`, `haiku`)?

"Yes" to any of these is a signal to reconsider, but use judgment. Some context is helpful; the question is whether you're constraining vs. informing.
Expand Down
2 changes: 1 addition & 1 deletion docs/guides/github-automation.md
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ handles correctness, security, and style. Design Review focuses exclusively on:
| Rigid procedures | Micromanaging step-by-step procedures when objectives would suffice |
| Prompt-level security | Using instructions for constraints that should be sandbox-enforced |
| Direct LLM API calls outside sandbox | Calling the Anthropic API from orchestrator, gateway, or shared code instead of delegating to sandbox containers (enforced by EGG200 linter) |
| Direct API calls bypassing Claude Code | Using raw HTTP calls to the Anthropic API instead of `claude --print` (Claude Code headless mode), which provides tool access and consistent configuration |
| Direct API calls bypassing the Agent SDK | Using raw HTTP calls to the Anthropic API instead of `run_agent()` (in-sandbox) or `build_agent_command()` (orchestrator-spawned containers), which provide tool access and consistent configuration |
| Hardcoded model identifiers | Using full model IDs like `claude-sonnet-4-20250514` instead of short aliases (`sonnet`, `opus`, `haiku`) which auto-adopt the latest version (enforced by EGG201 linter) |

### Review Philosophy
Expand Down
8 changes: 4 additions & 4 deletions orchestrator/routes/pipelines.py
Original file line number Diff line number Diff line change
Expand Up @@ -968,10 +968,10 @@ def _get_agent_design_criteria() -> str:
"sandbox-enforced\n"
"6. **Direct LLM API calls outside sandbox** — Calling the Anthropic API from "
"orchestrator, gateway, or shared code instead of delegating to sandbox containers\n"
"7. **Direct API calls bypassing Claude Code** — Using raw HTTP calls to the "
"Anthropic API instead of claude --print (Claude Code headless mode). "
"Unlike item 6 (scoped to infra code), this applies everywhere including "
"sandbox code.\n"
"7. **Direct API calls bypassing the Agent SDK** — Using raw HTTP calls to the "
"Anthropic API instead of run_agent() (in-sandbox) or build_agent_command() "
"(orchestrator-spawned containers). Unlike item 6 (scoped to infra code), "
"this applies everywhere including sandbox code.\n"
"8. **Hardcoded model identifiers** — Using full model IDs (date-pinned or "
"version-pinned) instead of short aliases (sonnet, opus, haiku)\n"
)
Expand Down
30 changes: 30 additions & 0 deletions shared/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,36 @@ Reusable Python libraries shared between the gateway sidecar and sandbox contain

## Packages

### egg_agent

Claude Agent SDK wrapper for in-sandbox agent execution and orchestrator command building.

- `run_agent()` / `run_agent_async()` — run a Claude agent in-process via `claude-agent-sdk`
- `build_agent_command()` — build the `claude --print` command list for orchestrator-spawned containers
- `AgentResult` — dataclass with response text, success flag, and SDK metadata (cost, turns, duration)

```python
# In-sandbox: call another agent in-process
from egg_agent import AgentResult
from egg_agent.client import run_agent

result = run_agent("Inspect this code for issues", model="sonnet", max_turns=1)
if result.success:
print(result.stdout)

# In orchestrator: build a container command
from egg_agent import build_agent_command

cmd = build_agent_command("Fix the bug", model="opus", max_turns=200)
spawner.spawn_agent_container(..., command=cmd)
```

**Files:**
- `client.py` — `run_agent()`, `run_agent_async()` using `claude-agent-sdk`
- `command.py` — `build_agent_command()` for orchestrator-spawned containers
- `result.py` — `AgentResult` dataclass
- `__main__.py` — CLI entry point (`python3 -m egg_agent "prompt"`)

### [egg_config](egg_config/README.md)

Unified configuration framework for egg services.
Expand Down
2 changes: 1 addition & 1 deletion shared/prompts/agent-design-criteria.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Flag these **clear** anti-patterns:
4. **Rigid procedures**: Micromanaging step-by-step procedures when objectives would suffice
5. **Prompt-level security**: Using instructions for constraints that should be sandbox-enforced
6. **Direct LLM API calls outside sandbox**: Calling the Anthropic API (via `httpx`, `requests`, or the Anthropic SDK) from orchestrator, gateway, or shared code instead of delegating to sandbox containers (enforced by `EGG200` linter)
7. **Direct API calls bypassing Claude Code**: Using raw HTTP calls to the Anthropic API instead of `claude --print` (Claude Code headless mode), which provides tool access and consistent configuration. Unlike item 6 (which is scoped to infra code), this applies everywhere including sandbox code.
7. **Direct API calls bypassing the Agent SDK**: Using raw HTTP calls to the Anthropic API instead of `egg_agent.client.run_agent()` (in-sandbox) or `build_agent_command()` (orchestrator-spawned containers), which provide tool access and consistent configuration. Unlike item 6 (which is scoped to infra code), this applies everywhere including sandbox code.
8. **Hardcoded model identifiers**: Using full model IDs like `claude-sonnet-4-20250514` instead of short aliases (`sonnet`, `opus`, `haiku`) which auto-adopt the latest version (enforced by `EGG201` linter)

## What to Skip
Expand Down
Loading