Skip to content
Open
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
20 changes: 14 additions & 6 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -66,19 +66,27 @@ FORGE_REQUIRE_PROJECT_CONFIG=true

# =============================================================================
# LLM Configuration
# Supports Claude (via Anthropic API or Vertex AI) and Gemini (via Vertex AI)
# Forge passes LangChain chat model instances into Deep Agents. Built-in
# configuration supports direct Anthropic API credentials and Vertex AI-backed
# model access. Additional LangChain chat models can be wired in by extending
# the model factory.
# =============================================================================

# Option 1: Direct Anthropic API (Claude models only)
# Option 1: Direct Anthropic API.
LLM_API_KEY=
# Backwards-compatible name for Anthropic direct API deployments.
ANTHROPIC_API_KEY=
# Option 2: Google Vertex AI (supports both Claude and Gemini)

# Option 2: Google Vertex AI.
VERTEX_PROJECT_ID=your-gcp-project-id
VERTEX_REGION=us-east5
# Backwards-compatible names for existing deployments.
ANTHROPIC_VERTEX_PROJECT_ID=your-gcp-project-id
ANTHROPIC_VERTEX_REGION=us-east5

# Model for orchestrator (PRD, spec, epic planning)
# Claude models: claude-opus-4-5@20251101, claude-sonnet-4-5@20250929, claude-haiku-4-5@20251001
# Gemini models: gemini-2.5-pro, gemini-2.5-flash, gemini-3.1-pro-preview
LLM_MODEL=claude-opus-4-5@20251101
# Examples: gemini-3.5-flash, gemini-2.5-pro, claude-opus-4-5@20251101
LLM_MODEL=claude-sonnet-4-5@20250929

# Model for container tasks (code implementation)
# Can use a different model than orchestrator (e.g., for cost/rate limit reasons)
Expand Down
20 changes: 11 additions & 9 deletions containers/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ Based on `mcr.microsoft.com/devcontainers/universal:linux` which provides:

Additional packages installed:
- `deepagents` - AI agent framework
- `anthropic`, `langchain-anthropic` - Claude API access
- `langchain-google-vertexai` - Vertex AI support (Claude and Gemini)
- `anthropic`, `langchain-anthropic` - direct Anthropic API access
- `langchain-google-vertexai` - Vertex AI model access
- `langchain-mcp-adapters` - MCP server integration

## Image Configuration
Expand Down Expand Up @@ -104,10 +104,11 @@ Passed automatically by the orchestrator:

| Variable | Description |
|----------|-------------|
| `ANTHROPIC_API_KEY` | Claude API key (direct API) |
| `ANTHROPIC_VERTEX_PROJECT_ID` | GCP project for Vertex AI |
| `ANTHROPIC_VERTEX_REGION` | Vertex AI region |
| `LLM_MODEL` | Model to use (e.g., `claude-opus-4-5@20251101`, `gemini-2.5-pro`) |
| `LLM_API_KEY` | Direct Anthropic API key |
| `VERTEX_PROJECT_ID` | GCP project for Vertex AI |
| `VERTEX_REGION` | Vertex AI region |
| `ANTHROPIC_*` | Backwards-compatible aliases for existing deployments |
| `LLM_MODEL` | Model to use (default: `claude-sonnet-4-5@20250929`; examples: `gemini-3.5-flash`, `gemini-2.5-pro`, `claude-opus-4-5@20251101`) |
| `FORGE_SYSTEM_PROMPT_TEMPLATE` | System prompt template (interpolated by entrypoint) |
| `GOOGLE_APPLICATION_CREDENTIALS` | Path to mounted gcloud credentials |
| `GIT_USER_NAME` | Git author name for commits (default: `Forge`) |
Expand Down Expand Up @@ -136,9 +137,10 @@ Example: `forge-AISOS-189-installer-12345`

## Task Execution

The entrypoint runs a Deep Agent with `LocalShellBackend`. Supported models:
- **Claude** (via Anthropic API or Vertex AI): `claude-opus-4-5@20251101`, `claude-sonnet-4-5@20250929`
- **Gemini** (via Vertex AI): `gemini-2.5-pro`, `gemini-2.5-flash`, `gemini-3.1-pro-preview`
The entrypoint runs a Deep Agent with `LocalShellBackend`. Built-in model
factory support covers direct Anthropic API credentials and Vertex AI-backed
models. Because the agent receives a LangChain chat model instance, additional
providers can be added by extending the model factory.

The agent:
1. Reads and understands the codebase
Expand Down
62 changes: 37 additions & 25 deletions containers/entrypoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
if os.environ.get("LANGCHAIN_VERBOSE", "").lower() in ("true", "1", "yes"):
try:
from langchain_core.globals import set_debug, set_verbose

set_verbose(True)
set_debug(True)
logger.info("LangChain verbose/debug mode enabled")
Expand Down Expand Up @@ -303,23 +304,29 @@ async def run_agent_task(
guardrails: Repository guidelines.
previous_task_keys: List of previously implemented task keys for handoff context.
"""
# Support both new (LLM_MODEL) and legacy (CLAUDE_MODEL) env var names
model_name = os.environ.get("LLM_MODEL") or os.environ.get("CLAUDE_MODEL", "claude-sonnet-4-5@20250929")
# Support both generic (LLM_MODEL) and legacy (CLAUDE_MODEL) env var names.
model_name = os.environ.get("LLM_MODEL") or os.environ.get(
"CLAUDE_MODEL", "claude-sonnet-4-5@20250929"
)
logger.info(f"Implementing task: {task_summary}")
logger.info(f"Model: {model_name}")

try:
from deepagents import create_deep_agent
from deepagents.backends import LocalShellBackend

# Check for API credentials
api_key = os.environ.get("ANTHROPIC_API_KEY")
vertex_project = os.environ.get("ANTHROPIC_VERTEX_PROJECT_ID")
# Check for API credentials. ANTHROPIC_* names are accepted for
# compatibility with existing deployments and LangChain integrations.
api_key = os.environ.get("LLM_API_KEY") or os.environ.get("ANTHROPIC_API_KEY")
vertex_project = os.environ.get("VERTEX_PROJECT_ID") or os.environ.get(
"ANTHROPIC_VERTEX_PROJECT_ID"
)
vertex_region = os.environ.get("VERTEX_REGION") or os.environ.get(
"ANTHROPIC_VERTEX_REGION", "us-east5"
)

if not api_key and not vertex_project:
logger.error(
"No API credentials found (ANTHROPIC_API_KEY or ANTHROPIC_VERTEX_PROJECT_ID)"
)
logger.error("No model backend credentials found (LLM_API_KEY or VERTEX_PROJECT_ID)")
return False

# Create the agent with local shell backend (enables git commands)
Expand All @@ -337,34 +344,36 @@ async def run_agent_task(
workspace, task_key, task_summary, task_description, guardrails, previous_task_keys
)

# Determine model type (Gemini vs Claude)
# Determine model family for the built-in LangChain model factories.
is_gemini = model_name.lower().startswith(("gemini", "models/gemini"))

# Get max tokens from env (default 16384)
max_tokens = int(os.environ.get("LLM_MAX_TOKENS", "16384"))

if vertex_project:
if is_gemini:
# Gemini models via ChatGoogleGenerativeAI with Vertex AI backend
from langchain_google_genai import ChatGoogleGenerativeAI

logger.info(f"Using Gemini model: {model_name}, max_output_tokens={max_tokens}")
logger.info(
f"Using Vertex AI Gemini model: {model_name}, max_output_tokens={max_tokens}"
)
model = ChatGoogleGenerativeAI(
model=model_name,
project=vertex_project,
location=os.environ.get("ANTHROPIC_VERTEX_REGION", "us-east5"),
location=vertex_region,
vertexai=True,
max_output_tokens=max_tokens,
)
else:
# Claude models via ChatAnthropicVertex
from langchain_google_vertexai.model_garden import ChatAnthropicVertex

logger.info(f"Using Claude model: {model_name}, max_tokens={max_tokens}")
logger.info(
f"Using Vertex AI Anthropic model: {model_name}, max_tokens={max_tokens}"
)
model = ChatAnthropicVertex(
model_name=model_name,
project=vertex_project,
location=os.environ.get("ANTHROPIC_VERTEX_REGION", "us-east5"),
location=vertex_region,
max_tokens=max_tokens,
)
else:
Expand All @@ -374,7 +383,7 @@ async def run_agent_task(

from langchain_anthropic import ChatAnthropic

logger.info(f"Using Claude model: {model_name}, max_tokens={max_tokens}")
logger.info(f"Using direct Anthropic model: {model_name}, max_tokens={max_tokens}")
model = ChatAnthropic(
model=model_name,
api_key=api_key,
Expand Down Expand Up @@ -442,9 +451,7 @@ async def run_agent_task(

# Run the agent (with Langfuse session context if enabled)
initial_message = {
"messages": [
{"role": "user", "content": f"Implement this task:\n\n{task_description}"}
]
"messages": [{"role": "user", "content": f"Implement this task:\n\n{task_description}"}]
}

if langfuse_enabled:
Expand Down Expand Up @@ -592,13 +599,18 @@ def main():
# Ensure changes are committed (agent should have done this, but as fallback).
# Skip if workspace is not a git repo — analysis tasks (RCA, reflection) write
# artifacts to .forge/ without needing a commit.
is_git_repo = subprocess.run(
["git", "rev-parse", "--is-inside-work-tree"],
cwd=workspace,
capture_output=True,
).returncode == 0
is_git_repo = (
subprocess.run(
["git", "rev-parse", "--is-inside-work-tree"],
cwd=workspace,
capture_output=True,
).returncode
== 0
)
if is_git_repo:
fallback_message = f"[{task_key}] {task_summary}\n\nAuto-committed by Forge container fallback."
fallback_message = (
f"[{task_key}] {task_summary}\n\nAuto-committed by Forge container fallback."
)
if not git_commit(workspace, fallback_message):
logger.error("Failed to commit changes")
sys.exit(EXIT_TASK_FAILED)
Expand Down
6 changes: 3 additions & 3 deletions docs/dev/setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ This page is a condensed reference. For the full walkthrough including payload-b
| Podman | `brew install podman` / `dnf install podman` |
| Docker Compose | Included with Docker Desktop or `brew install docker-compose` |

External accounts needed: Jira Cloud, GitHub, and Anthropic API key (or Vertex AI).
External accounts needed: Jira Cloud, GitHub, and LLM backend access through a direct model provider API or Vertex AI.

## Installation

Expand All @@ -33,9 +33,9 @@ JIRA_API_TOKEN=your-jira-api-token

GITHUB_TOKEN=github_pat_your_token

ANTHROPIC_API_KEY=sk-ant-your-key # or Vertex AI — see developer guide
LLM_API_KEY=your-anthropic-api-key # or Vertex AI — see developer guide

LLM_MODEL=claude-opus-4-5@20251101
LLM_MODEL=claude-sonnet-4-5@20250929
REDIS_URL=redis://localhost:6380/0
```

Expand Down
16 changes: 8 additions & 8 deletions docs/developer-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Everything you need to run Forge locally, test it, observe what it's doing, and
- **Docker Compose** — for Redis and API gateway (`dnf install docker-compose` / included with Docker Desktop)
- **Jira Cloud** account with API access
- **GitHub** account with a Personal Access Token (scopes: `repo`, `read:org`)
- **Claude API key** (Anthropic direct) OR Google Cloud project with Vertex AI enabled
- **LLM backend access** through a direct model provider API OR Google Cloud project with Vertex AI enabled

---

Expand Down Expand Up @@ -69,15 +69,15 @@ GITHUB_TOKEN=github_pat_your_token

# LLM — choose one backend

# Option A: Anthropic direct
ANTHROPIC_API_KEY=sk-ant-your-key
# Option A: Direct Anthropic API
LLM_API_KEY=your-anthropic-api-key

# Option B: Google Vertex AI (supports Claude + Gemini)
ANTHROPIC_VERTEX_PROJECT_ID=your-gcp-project
ANTHROPIC_VERTEX_REGION=us-east5
# Option B: Google Vertex AI
VERTEX_PROJECT_ID=your-gcp-project
VERTEX_REGION=us-east5

# Which model to use
LLM_MODEL=claude-opus-4-5@20251101
LLM_MODEL=claude-sonnet-4-5@20250929
```

---
Expand Down Expand Up @@ -506,7 +506,7 @@ forge_webhooks_failed_total
# External API latency
forge_external_api_latency_seconds{service="jira"}
forge_external_api_latency_seconds{service="github"}
forge_external_api_latency_seconds{service="claude"}
forge_external_api_latency_seconds{service="llm"}
```

### Adding worker metrics to Prometheus
Expand Down
12 changes: 6 additions & 6 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Get Forge running locally in about 10 minutes.
- **Docker Compose** — for Redis (`brew install docker-compose` / included with Docker Desktop)
- **Jira Cloud** account with API access
- **GitHub** Personal Access Token (scopes: `repo`, `read:org`)
- **Claude API key** (Anthropic direct) or Google Cloud project with Vertex AI enabled
- **LLM backend access** through a direct model provider API or Google Cloud project with Vertex AI enabled

## 1. Install

Expand All @@ -36,12 +36,12 @@ JIRA_API_TOKEN=your-jira-api-token
# GitHub
GITHUB_TOKEN=github_pat_your_token

# LLM — choose one
ANTHROPIC_API_KEY=sk-ant-your-key # Anthropic direct
# ANTHROPIC_VERTEX_PROJECT_ID=my-proj # OR Vertex AI
# ANTHROPIC_VERTEX_REGION=us-east5
# LLM backend — choose one
LLM_API_KEY=your-anthropic-api-key # Direct Anthropic API
# VERTEX_PROJECT_ID=my-proj # OR Vertex AI
# VERTEX_REGION=us-east5

LLM_MODEL=claude-opus-4-5@20251101
LLM_MODEL=claude-sonnet-4-5@20250929
```

## 3. Build the Container Image
Expand Down
2 changes: 1 addition & 1 deletion docs/guide/pr-commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ Merge `main` into the PR branch and resolve any merge conflicts using AI. Use th
3. Clones the repository and checks out the PR branch from the fork
4. Attempts `git merge origin/main`
5. If no conflicts: pushes the merge commit to the fork branch
6. If conflicts: spawns a container with Claude to resolve them using the PR description and changed files as context
6. If conflicts: spawns a container agent to resolve them using the PR description and changed files as context
7. Verifies no conflict markers remain, commits, and force-pushes to the fork
8. Returns the workflow to the node it was at before the rebase

Expand Down
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Forge

Forge automates the software development lifecycle from feature ideation through code delivery using AI-powered planning and execution. It connects Jira, GitHub, and Claude to transform tickets into shipped code with human approval gates at each stage.
Forge automates the software development lifecycle from feature ideation through code delivery using AI-powered planning and execution. It connects Jira, GitHub, and Deep Agents-backed LangChain models to transform tickets into shipped code with human approval gates at each stage.

## How It Works

Expand Down
19 changes: 12 additions & 7 deletions docs/reference/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,28 @@ All configuration is via environment variables in `.env`. See `.env.example` in

### LLM

Choose one backend:
Choose one backend. Forge passes LangChain chat model instances into Deep Agents; the
built-in factory supports direct Anthropic API credentials and Vertex AI-backed
models, and can be extended for other LangChain chat model providers.

=== "Anthropic Direct"
=== "Direct Anthropic API"

```bash
ANTHROPIC_API_KEY=sk-ant-your-key
LLM_MODEL=claude-opus-4-5@20251101
LLM_API_KEY=your-anthropic-api-key
LLM_MODEL=claude-sonnet-4-5@20250929
```

=== "Google Vertex AI"

```bash
ANTHROPIC_VERTEX_PROJECT_ID=your-gcp-project
ANTHROPIC_VERTEX_REGION=us-east5
LLM_MODEL=claude-opus-4-5@20251101
VERTEX_PROJECT_ID=your-gcp-project
VERTEX_REGION=us-east5
LLM_MODEL=gemini-3.5-flash
```

`ANTHROPIC_API_KEY`, `ANTHROPIC_VERTEX_PROJECT_ID`, and
`ANTHROPIC_VERTEX_REGION` remain supported as backwards-compatible aliases.

### Redis

| Variable | Default | Description |
Expand Down
6 changes: 3 additions & 3 deletions src/forge/api/routes/metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@
[
"service",
"operation",
], # service: jira, github, claude; operation: get_issue, create_pr, etc.
], # service: jira, github, llm; operation: get_issue, create_pr, etc.
buckets=[0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 30.0],
)

Expand Down Expand Up @@ -216,7 +216,7 @@ def observe_external_api_latency(service: str, operation: str, duration: float)
"""Record latency of an external API call.

Args:
service: External service name (jira, github, claude).
service: External service name (jira, github, llm).
operation: Operation name (get_issue, create_pr, generate, etc.).
duration: Duration in seconds.
"""
Expand All @@ -227,7 +227,7 @@ def record_external_api_error(service: str, operation: str, error_type: str) ->
"""Record an external API call error.

Args:
service: External service name (jira, github, claude).
service: External service name (jira, github, llm).
operation: Operation name.
error_type: Type of error (timeout, rate_limit, auth, etc.).
"""
Expand Down
10 changes: 5 additions & 5 deletions src/forge/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -675,13 +675,13 @@ async def cmd_health(_args: argparse.Namespace) -> int:
else:
print("[SKIP] Jira: API token not configured")

# Check Anthropic/Vertex
# Check model backend
if settings.use_vertex_ai:
print(f"[OK] Using Vertex AI: {settings.anthropic_vertex_project_id}")
elif settings.anthropic_api_key.get_secret_value():
print("[OK] Using direct Anthropic API")
print(f"[OK] Using Vertex AI: {settings.resolved_vertex_project_id}")
elif settings.direct_llm_api_key.get_secret_value():
print("[OK] Using direct model provider API")
else:
print("[WARN] No Claude API configured")
print("[WARN] No LLM backend configured")

print("\nHealth check complete!")
return 0
Expand Down
Loading
Loading