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
28 changes: 0 additions & 28 deletions Dockerfile.codex-automation

This file was deleted.

22 changes: 10 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Async Code Agent
# Claude Code UI

Use Claude Code / CodeX CLI to perform multiple tasks in parallel with a Codex-style UI.
Use Claude Code to perform multiple tasks in parallel with a Claude Code-style UI.

A code agent task management system that provides parallel execution of AI-powered coding tasks. Users can run multiple Claude Code agents simultaneously through a Codex-style web interface, with support for different agents for comparison and evaluation.
A code agent task management system that provides parallel execution of Claude Code automation tasks. Users can run multiple Claude Code agents simultaneously through a web interface focused on Claude Code integration.

![async-code-ui](https://github.com/user-attachments/assets/e490c605-681a-4abb-a440-323e15f1a90d)

Expand All @@ -12,19 +12,18 @@ A code agent task management system that provides parallel execution of AI-power

## Key Features

- 🤖 **Multi-Agent Support**: Run Claude Code and other AI agents in parallel
- 🤖 **Claude Code Integration**: Run Claude Code automation tasks in parallel
- 🔄 **Parallel Task Management**: Execute multiple coding tasks simultaneously
- 🌐 **Codex-Style Web UI**: Clean interface for managing agent tasks
- 🔍 **Agent Comparison**: Compare outputs from different AI models
- 🌐 **Clean Web UI**: Modern interface for managing Claude Code tasks
- 🐳 **Containerized Execution**: Secure sandboxed environment for each task
- 🔗 **Git Integration**: Automatic repository cloning, commits, and PR creation
- **Selfhost**: Deploy you rown parallel code agent platform.
- **Selfhost**: Deploy your own parallel code agent platform.

## Architecture

- **Frontend**: Next.js with TypeScript and TailwindCSS
- **Backend**: Python Flask API with Docker orchestration
- **Agents**: Claude Code (Anthropic) with extensible support for other models
- **Agent**: Claude Code (Anthropic)
- **Task Management**: Parallel execution system based on container

## Quick Start
Expand Down Expand Up @@ -72,10 +71,9 @@ See `db/README.md` for detailed database setup instructions.

1. **Setup GitHub Token**: Enter your GitHub token in the web interface
2. **Configure Repository**: Specify target repository and branch
3. **Select Agent**: Choose your preferred AI agent (Claude Code, etc.)
4. **Submit Tasks**: Start multiple coding tasks in parallel
5. **Compare Results**: Review and compare outputs from different agents
6. **Create PRs**: Generate pull requests from successful tasks
3. **Submit Tasks**: Start multiple Claude Code tasks in parallel
4. **Review Results**: Review outputs from Claude Code automation
5. **Create PRs**: Generate pull requests from successful tasks

## Environment Variables

Expand Down
15 changes: 2 additions & 13 deletions async-code-web/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import { ApiService } from "@/lib/api-service";
import { SupabaseService } from "@/lib/supabase-service";
import { Project, Task } from "@/types";
import { ClaudeIcon } from "@/components/icon/claude";
import { OpenAIIcon } from "@/components/icon/openai";
import { toast } from "sonner";

interface TaskWithProject extends Task {
Expand Down Expand Up @@ -264,7 +263,6 @@ export default function Home() {
const getAgentIcon = (agent: string) => {
switch (agent) {
case "claude": return <ClaudeIcon className="w-3 h-3" />;
case "codex": return <OpenAIIcon className="w-3 h-3" />;
default: return null;
}
};
Expand Down Expand Up @@ -297,8 +295,8 @@ export default function Home() {
<Code2 className="w-4 h-4 text-white" />
</div>
<div>
<h1 className="text-xl font-semibold text-slate-900">Async Code</h1>
<p className="text-sm text-slate-500">Manage parallel AI code agents (Codex & Claude)</p>
<h1 className="text-xl font-semibold text-slate-900">Claude Code UI</h1>
<p className="text-sm text-slate-500">Manage parallel Claude Code automation tasks</p>
</div>
</div>
<div className="flex items-center gap-4">
Expand Down Expand Up @@ -462,15 +460,6 @@ export default function Home() {
</div>
</div>
</SelectItem>
<SelectItem value="codex">
<div className="flex items-center gap-3">
<OpenAIIcon className="w-4 h-4 flex-shrink-0" />
<div className="flex items-center gap-2">
<span className="font-medium">Codex</span>
<span className="text-xs text-slate-500">• OpenAI's lightweight coding agent</span>
</div>
</div>
</SelectItem>
</SelectContent>
</Select>
</div>
Expand Down
4 changes: 2 additions & 2 deletions async-code-web/app/signin/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ export default function SignIn() {
<Code2 className="w-6 h-6 text-white" />
</div>
<h1 className="text-2xl font-bold text-slate-900 mb-2">
Welcome to AI Code Automation
Welcome to Claude Code Automation
</h1>
<p className="text-slate-600">
Sign in to start automating your code with Claude Code & Codex CLI
Sign in to start automating your code with Claude Code
</p>
</div>

Expand Down
90 changes: 7 additions & 83 deletions async-code-web/components/code-agent-settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@ interface CodeAgentConfig {
env?: Record<string, string>;
credentials?: Record<string, any> | null;
};
codex?: {
env?: Record<string, string>;
};
}

const DEFAULT_CLAUDE_ENV = {
Expand All @@ -32,13 +29,6 @@ const DEFAULT_CLAUDE_CREDENTIALS = {
// Example structure - user can customize
};

const DEFAULT_CODEX_ENV = {
OPENAI_API_KEY: "",
DISABLE_SANDBOX: "yes",
CONTINUE_ON_BROWSER: "no",
// Add other Codex-specific env vars here if needed
};

// Helper function to check if credentials is meaningful (not empty/null/undefined)
const hasMeaningfulCredentials = (creds: any): boolean => {
if (!creds || creds === null || creds === undefined || creds === '') {
Expand All @@ -54,12 +44,10 @@ export function CodeAgentSettings() {
const { profile, refreshProfile } = useUserProfile();
const [claudeEnv, setClaudeEnv] = useState("");
const [claudeCredentials, setClaudeCredentials] = useState("");
const [codexEnv, setCodexEnv] = useState("");
const [isLoading, setIsLoading] = useState(false);
const [errors, setErrors] = useState<{
claudeEnv?: string;
claudeCredentials?: string;
codexEnv?: string;
}>({});

// Load settings from profile on mount
Expand All @@ -84,28 +72,11 @@ export function CodeAgentSettings() {
}
}

// Handle backward compatibility for Codex config
let codexConfig: any = {};
if (prefs.codex) {
// Check if it's the new structure
if (prefs.codex.env) {
codexConfig = prefs.codex;
} else {
// New structure for codex
codexConfig = { env: prefs.codex };
}
} else if (prefs.codexCLI) {
// Old codexCLI key - migrate to new codex key
codexConfig = { env: prefs.codexCLI };
}

setClaudeEnv(JSON.stringify(claudeConfig.env || DEFAULT_CLAUDE_ENV, null, 2));
setClaudeCredentials(JSON.stringify(claudeConfig.credentials || DEFAULT_CLAUDE_CREDENTIALS, null, 2));
setCodexEnv(JSON.stringify(codexConfig.env || DEFAULT_CODEX_ENV, null, 2));
} else {
setClaudeEnv(JSON.stringify(DEFAULT_CLAUDE_ENV, null, 2));
setClaudeCredentials(JSON.stringify(DEFAULT_CLAUDE_CREDENTIALS, null, 2));
setCodexEnv(JSON.stringify(DEFAULT_CODEX_ENV, null, 2));
}
}, [profile]);

Expand All @@ -124,9 +95,8 @@ export function CodeAgentSettings() {
// Validate all JSONs
const isClaudeEnvValid = validateJSON(claudeEnv, "claudeEnv");
const isClaudeCredentialsValid = validateJSON(claudeCredentials, "claudeCredentials");
const isCodexEnvValid = validateJSON(codexEnv, "codexEnv");

if (!isClaudeEnvValid || !isClaudeCredentialsValid || !isCodexEnvValid) {
if (!isClaudeEnvValid || !isClaudeCredentialsValid) {
toast.error("Please fix JSON errors before saving");
return;
}
Expand All @@ -135,23 +105,19 @@ export function CodeAgentSettings() {
try {
const claudeEnvConfig = JSON.parse(claudeEnv);
const claudeCredentialsConfig = JSON.parse(claudeCredentials);
const codexEnvConfig = JSON.parse(codexEnv);

const preferences: CodeAgentConfig = {
claudeCode: {
env: claudeEnvConfig,
credentials: hasMeaningfulCredentials(claudeCredentialsConfig) ? claudeCredentialsConfig : null,
},
codex: {
env: codexEnvConfig,
},
};

// Merge with existing preferences if any
const existingPrefs = (profile?.preferences || {}) as Record<string, any>;

// Clean up old keys during migration
const { codexCLI, ...cleanedPrefs } = existingPrefs;
// Clean up old Codex keys during migration
const { codexCLI, codex, ...cleanedPrefs } = existingPrefs;

const mergedPrefs = {
...cleanedPrefs,
Expand All @@ -166,7 +132,7 @@ export function CodeAgentSettings() {
? "Claude credentials will be configured"
: "Claude credentials are empty and will be skipped";

toast.success(`Code agent settings saved successfully. ${credentialsMessage}`);
toast.success(`Claude Code settings saved successfully. ${credentialsMessage}`);
} catch (error) {
console.error("Failed to save settings:", error);
toast.error("Failed to save settings");
Expand All @@ -179,9 +145,9 @@ export function CodeAgentSettings() {
<div className="space-y-6">
<Card>
<CardHeader>
<CardTitle>Code Agent Settings</CardTitle>
<CardTitle>Claude Code Settings</CardTitle>
<CardDescription>
Configure environment variables and credentials for each code agent. These settings will be used when creating containers.
Configure environment variables and credentials for Claude Code. These settings will be used when creating containers.
</CardDescription>
</CardHeader>
<CardContent className="space-y-8">
Expand Down Expand Up @@ -256,51 +222,9 @@ export function CodeAgentSettings() {
</div>
</div>

{/* Codex CLI Settings */}
<div className="space-y-6">
<div className="flex items-center gap-2 pb-2 border-b">
<Settings2 className="w-5 h-5 text-green-600" />
<h3 className="text-lg font-semibold">Codex CLI Configuration</h3>
</div>

{/* Codex Environment Variables */}
<div className="space-y-2">
<Label htmlFor="codex-env" className="flex items-center gap-2">
<Settings2 className="w-4 h-4" />
Environment Variables
</Label>
<div className="border rounded-lg overflow-hidden">
<CodeMirror
id="codex-env"
value={codexEnv}
height="200px"
extensions={[javascript({ jsx: false })]}
theme={githubLight}
onChange={(value) => {
setCodexEnv(value);
validateJSON(value, "codexEnv");
}}
placeholder={JSON.stringify(DEFAULT_CODEX_ENV, null, 2)}
/>
</div>
{errors.codexEnv && (
<p className="text-sm text-red-500 mt-1">{errors.codexEnv}</p>
)}
<p className="text-sm text-muted-foreground">
Configure environment variables for Codex CLI (@openai/codex)
</p>
</div>

<div className="p-3 bg-yellow-50 border border-yellow-200 rounded-md">
<p className="text-sm text-yellow-800">
<strong>Note:</strong> Codex CLI does not require separate credentials configuration. All settings are handled via environment variables.
</p>
</div>
</div>

<Button
onClick={handleSave}
disabled={isLoading || !!errors.claudeEnv || !!errors.claudeCredentials || !!errors.codexEnv}
disabled={isLoading || !!errors.claudeEnv || !!errors.claudeCredentials}
className="w-full"
>
<Save className="w-4 h-4 mr-2" />
Expand Down
6 changes: 3 additions & 3 deletions server/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ def start_task():
if not all([prompt, repo_url, github_token]):
return jsonify({'error': 'prompt, repo_url, and github_token are required'}), 400

# Validate model selection
if model not in ['claude', 'codex']:
return jsonify({'error': 'model must be either "claude" or "codex"'}), 400
# Validate model selection - only claude is supported
if model != 'claude':
return jsonify({'error': 'model must be "claude"'}), 400

# Create initial chat message
chat_messages = [{
Expand Down
Loading