Skip to content

Commit bd0c5a6

Browse files
Add Codex CLI support and model selection feature (#2)
Co-authored-by: Cursor Agent <[email protected]>
1 parent bf56235 commit bd0c5a6

File tree

5 files changed

+108
-23
lines changed

5 files changed

+108
-23
lines changed

Dockerfile.claude-automation

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ RUN apk add --no-cache \
1212
# Install Claude Code globally
1313
RUN npm install -g @anthropic-ai/claude-code
1414

15+
# Install Codex CLI globally
16+
# Based on the GitHub repo, Codex is available as a npm package
17+
RUN npm install -g codex
18+
1519
# Create workspace directory
1620
WORKDIR /workspace
1721

README.md

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,24 @@
11
# Claude Code Automation MVP
22

3-
An MVP application that automates coding tasks using Claude Code in sandboxed environments. Users can submit text prompts describing what they want to develop for a configured GitHub repository, and Claude Code will analyze the codebase, make the necessary changes, and create commits that can be turned into pull requests.
3+
An MVP application that automates coding tasks using Claude Code or Codex CLI in sandboxed environments. Users can submit text prompts describing what they want to develop for a configured GitHub repository, and the selected AI model will analyze the codebase, make the necessary changes, and create commits that can be turned into pull requests.
44

55
## Features
66

7-
- 🤖 **Claude Code Integration**: Leverages Claude Code for intelligent code generation and modification
8-
- 🐳 **Sandboxed Execution**: Runs Claude Code in isolated Docker containers for security
7+
- 🤖 **Multiple AI Models**: Choose between Claude Code and Codex CLI for code generation
8+
- 🐳 **Sandboxed Execution**: Runs AI models in isolated Docker containers for security
99
- 🔄 **Git Integration**: Automatically clones repositories, makes commits, and creates pull requests
1010
- 🌐 **Web Interface**: Clean, modern UI for submitting prompts and reviewing changes
1111
- 📊 **Real-time Status**: Live updates on task progress and completion
1212
- 🔍 **Git Diff Viewer**: Review all changes before creating pull requests
13+
- 🎯 **Model Comparison**: Easily compare outputs from different AI models
1314

1415
## Architecture
1516

1617
- **Frontend**: Next.js with TypeScript and TailwindCSS
1718
- **Backend**: Python Flask API with Docker orchestration
18-
- **Automation**: Claude Code running in isolated Alpine Linux containers
19+
- **AI Models**:
20+
- Claude Code (Anthropic) - Advanced coding model
21+
- Codex CLI (OpenAI) - Lightweight coding agent
1922
- **Git Operations**: GitHub API integration for repository management
2023

2124
## Prerequisites
@@ -50,10 +53,11 @@ An MVP application that automates coding tasks using Claude Code in sandboxed en
5053

5154
1. **Setup GitHub Token**: Click "Setup GitHub Token" in the frontend and enter your token
5255
2. **Configure Repository**: Enter the GitHub repository URL and branch
53-
3. **Enter Prompt**: Describe what you want Claude Code to develop
54-
4. **Start Task**: Click "Code" to begin the automation process
55-
5. **Review Changes**: View the git diff when the task completes
56-
6. **Create PR**: If satisfied with changes, click "Create PR"
56+
3. **Select AI Model**: Choose between Claude Code or Codex CLI
57+
4. **Enter Prompt**: Describe what you want the AI to develop
58+
5. **Start Task**: Click "Code" to begin the automation process
59+
6. **Review Changes**: View the git diff when the task completes
60+
7. **Create PR**: If satisfied with changes, click "Create PR"
5761

5862
## Example Prompts
5963

@@ -74,8 +78,8 @@ FLASK_DEBUG=True
7478

7579
## API Endpoints
7680

77-
- `POST /start-task` - Start a new Claude Code automation task
78-
- `GET /task-status/<task_id>` - Get task status and progress
81+
- `POST /start-task` - Start a new automation task (supports `model` parameter: "claude" or "codex")
82+
- `GET /task-status/<task_id>` - Get task status and progress (includes model used)
7983
- `GET /git-diff/<task_id>` - Retrieve git diff for completed tasks
8084
- `POST /create-pr/<task_id>` - Create a pull request from completed task
8185

async-code-web/app/page.tsx

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/com
99
import { Badge } from "@/components/ui/badge";
1010
import { Label } from "@/components/ui/label";
1111
import { Separator } from "@/components/ui/separator";
12+
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
1213

1314
interface Task {
1415
id: string;
1516
status: string;
1617
prompt: string;
1718
repo_url: string;
1819
branch: string;
20+
model?: string;
1921
commit_hash?: string;
2022
error?: string;
2123
created_at: number;
@@ -26,6 +28,7 @@ export default function Home() {
2628
const [repoUrl, setRepoUrl] = useState("https://github.com/ObservedObserver/streamlit-react");
2729
const [branch, setBranch] = useState("main");
2830
const [githubToken, setGithubToken] = useState("");
31+
const [model, setModel] = useState("claude");
2932
const [currentTask, setCurrentTask] = useState<Task | null>(null);
3033
const [gitDiff, setGitDiff] = useState("");
3134
const [isLoading, setIsLoading] = useState(false);
@@ -81,7 +84,8 @@ export default function Home() {
8184
prompt: prompt.trim(),
8285
repo_url: repoUrl,
8386
branch: branch,
84-
github_token: githubToken
87+
github_token: githubToken,
88+
model: model
8589
})
8690
});
8791

@@ -94,6 +98,7 @@ export default function Home() {
9498
prompt: prompt.trim(),
9599
repo_url: repoUrl,
96100
branch: branch,
101+
model: model,
97102
created_at: Date.now()
98103
});
99104
setGitDiff("");
@@ -111,14 +116,15 @@ export default function Home() {
111116
if (!currentTask || currentTask.status !== "completed") return;
112117

113118
try {
119+
const modelName = currentTask.model === 'codex' ? 'Codex' : 'Claude Code';
114120
const response = await fetch(`${API_BASE}/create-pr/${currentTask.id}`, {
115121
method: 'POST',
116122
headers: {
117123
'Content-Type': 'application/json',
118124
},
119125
body: JSON.stringify({
120-
title: `Claude Code: ${currentTask.prompt.substring(0, 50)}...`,
121-
body: `Automated changes generated by Claude Code.\n\nPrompt: ${currentTask.prompt}`
126+
title: `${modelName}: ${currentTask.prompt.substring(0, 50)}...`,
127+
body: `Automated changes generated by ${modelName}.\n\nPrompt: ${currentTask.prompt}`
122128
})
123129
});
124130

@@ -166,8 +172,8 @@ export default function Home() {
166172
<Code2 className="w-4 h-4 text-white" />
167173
</div>
168174
<div>
169-
<h1 className="text-xl font-semibold text-slate-900">Claude Code</h1>
170-
<p className="text-sm text-slate-500">AI-Powered Code Automation</p>
175+
<h1 className="text-xl font-semibold text-slate-900">AI Code Automation</h1>
176+
<p className="text-sm text-slate-500">Claude Code & Codex CLI Integration</p>
171177
</div>
172178
</div>
173179
<Button
@@ -190,7 +196,7 @@ export default function Home() {
190196
What are we coding next?
191197
</h2>
192198
<p className="text-slate-600">
193-
Describe what you want to build and Claude will analyze your repository and make the necessary changes
199+
Describe what you want to build and your selected AI model will analyze your repository and make the necessary changes
194200
</p>
195201
</div>
196202

@@ -278,6 +284,30 @@ export default function Home() {
278284
/>
279285
</div>
280286
</div>
287+
288+
{/* Model Selection */}
289+
<div className="space-y-2">
290+
<Label htmlFor="model" className="flex items-center gap-2">
291+
<Code2 className="w-3 h-3" />
292+
AI Model
293+
</Label>
294+
<Select value={model} onValueChange={setModel}>
295+
<SelectTrigger id="model">
296+
<SelectValue placeholder="Select an AI model" />
297+
</SelectTrigger>
298+
<SelectContent>
299+
<SelectItem value="claude">
300+
Claude Code - Anthropic's advanced coding model
301+
</SelectItem>
302+
<SelectItem value="codex">
303+
Codex CLI - OpenAI's lightweight coding agent
304+
</SelectItem>
305+
</SelectContent>
306+
</Select>
307+
<p className="text-sm text-slate-600">
308+
Choose between Claude Code or Codex CLI for your automation needs
309+
</p>
310+
</div>
281311
</div>
282312

283313
<div className="flex justify-end">
@@ -306,7 +336,7 @@ export default function Home() {
306336
{getStatusIcon(currentTask.status)}
307337
{currentTask.status}
308338
</Badge>
309-
Task Status
339+
Task Status {currentTask.model && `(${currentTask.model.toUpperCase()})`}
310340
</CardTitle>
311341
<CardDescription>
312342
{new Date(currentTask.created_at).toLocaleString()}{currentTask.repo_url}
@@ -371,7 +401,7 @@ export default function Home() {
371401
Ready to Start Coding
372402
</h3>
373403
<p className="text-slate-600 max-w-md mx-auto">
374-
Enter a detailed prompt describing what you want to build. Claude will analyze your repository
404+
Enter a detailed prompt describing what you want to build. Your selected AI model will analyze your repository
375405
and implement the necessary changes automatically.
376406
</p>
377407
</CardContent>

server/main.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,15 @@ def start_task():
6464
repo_url = data.get('repo_url')
6565
branch = data.get('branch', 'main')
6666
github_token = data.get('github_token')
67+
model = data.get('model', 'claude') # Default to claude for backward compatibility
6768

6869
if not all([prompt, repo_url, github_token]):
6970
return jsonify({'error': 'prompt, repo_url, and github_token are required'}), 400
7071

72+
# Validate model selection
73+
if model not in ['claude', 'codex']:
74+
return jsonify({'error': 'model must be either "claude" or "codex"'}), 400
75+
7176
# Generate unique task ID
7277
task_id = str(uuid.uuid4())
7378

@@ -79,6 +84,7 @@ def start_task():
7984
'repo_url': repo_url,
8085
'branch': branch,
8186
'github_token': github_token,
87+
'model': model,
8288
'container_id': None,
8389
'commit_hash': None,
8490
'git_diff': None,
@@ -116,6 +122,7 @@ def get_task_status(task_id):
116122
'prompt': task['prompt'],
117123
'repo_url': task['repo_url'],
118124
'branch': task['branch'],
125+
'model': task.get('model', 'claude'), # Include model in response
119126
'commit_hash': task.get('commit_hash'),
120127
'error': task.get('error'),
121128
'created_at': task['created_at']
@@ -194,7 +201,7 @@ def run_claude_code_task(task_id):
194201
task = tasks[task_id]
195202
task['status'] = TaskStatus.RUNNING
196203

197-
logger.info(f"Starting Claude Code task {task_id}")
204+
logger.info(f"Starting {task.get('model', 'claude').upper()} task {task_id}")
198205

199206
# Escape special characters in prompt for shell safety
200207
escaped_prompt = task['prompt'].replace('"', '\\"').replace('$', '\\$').replace('`', '\\`')
@@ -204,6 +211,9 @@ def run_claude_code_task(task_id):
204211
'ANTHROPIC_API_KEY': os.getenv('ANTHROPIC_API_KEY'),
205212
}
206213

214+
# Determine which CLI to use
215+
model_cli = task.get('model', 'claude')
216+
207217
# Create the command to run in container
208218
container_command = f'''
209219
set -e
@@ -217,10 +227,10 @@ def run_claude_code_task(task_id):
217227
git config user.email "[email protected]"
218228
git config user.name "Claude Code Automation"
219229
220-
echo "Starting Claude Code with prompt..."
230+
echo "Starting {model_cli.upper()} with prompt..."
221231
222-
# Run Claude Code with the prompt
223-
echo "{escaped_prompt}" | claude
232+
# Run the selected model CLI with the prompt
233+
echo "{escaped_prompt}" | {model_cli}
224234
225235
# Check if there are changes
226236
if git diff --quiet; then
@@ -230,7 +240,7 @@ def run_claude_code_task(task_id):
230240
231241
# Commit changes
232242
git add .
233-
git commit -m "Claude Code: {escaped_prompt[:100]}"
243+
git commit -m "{model_cli.capitalize()}: {escaped_prompt[:100]}"
234244
235245
# Get commit hash and diff
236246
echo "COMMIT_HASH=$(git rev-parse HEAD)"

test-model-selection.sh

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#!/bin/bash
2+
3+
echo "Testing Model Selection API..."
4+
5+
# Test Claude model
6+
echo "Testing Claude Code model..."
7+
curl -X POST http://localhost:5000/start-task \
8+
-H "Content-Type: application/json" \
9+
-d '{
10+
"prompt": "Add a test comment to README",
11+
"repo_url": "https://github.com/test/repo",
12+
"branch": "main",
13+
"github_token": "test_token",
14+
"model": "claude"
15+
}'
16+
17+
echo -e "\n\nTesting Codex CLI model..."
18+
curl -X POST http://localhost:5000/start-task \
19+
-H "Content-Type: application/json" \
20+
-d '{
21+
"prompt": "Add a test comment to README",
22+
"repo_url": "https://github.com/test/repo",
23+
"branch": "main",
24+
"github_token": "test_token",
25+
"model": "codex"
26+
}'
27+
28+
echo -e "\n\nTesting invalid model..."
29+
curl -X POST http://localhost:5000/start-task \
30+
-H "Content-Type: application/json" \
31+
-d '{
32+
"prompt": "Add a test comment to README",
33+
"repo_url": "https://github.com/test/repo",
34+
"branch": "main",
35+
"github_token": "test_token",
36+
"model": "invalid_model"
37+
}'

0 commit comments

Comments
 (0)