#!/usr/bin/env python3 """ Autonomous Coding Agent Demo ============================ A minimal harness demonstrating long-running autonomous coding with Claude. This script implements the two-agent pattern (initializer + coding agent) and incorporates all the strategies from the long-running agents guide. Example Usage: python autonomous_agent_demo.py --project-dir ./claude_clone_demo python autonomous_agent_demo.py --project-dir ./claude_clone_demo --max-iterations 5 """ import argparse import asyncio import os from pathlib import Path from agent import run_autonomous_agent # Configuration # DEFAULT_MODEL = "claude-haiku-4-5-20251001" # DEFAULT_MODEL = "claude-sonnet-4-5-20250929" DEFAULT_MODEL = "claude-opus-4-5-20251101" def parse_args() -> argparse.Namespace: """Parse command line arguments.""" parser = argparse.ArgumentParser( description="Autonomous Coding Agent Demo - Long-running agent harness", formatter_class=argparse.RawDescriptionHelpFormatter, epilog=""" Examples: # Start fresh project python autonomous_agent_demo.py --project-dir ./claude_clone # Use a specific model python autonomous_agent_demo.py --project-dir ./claude_clone --model claude-sonnet-4-5-20250929 # Limit iterations for testing python autonomous_agent_demo.py --project-dir ./claude_clone --max-iterations 5 # Continue existing project python autonomous_agent_demo.py --project-dir ./claude_clone Environment Variables: ANTHROPIC_API_KEY Your Anthropic API key (required) """, ) parser.add_argument( "--project-dir", type=Path, default=Path("./autonomous_demo_project"), help="Directory for the project (default: generations/autonomous_demo_project). Relative paths automatically placed in generations/ directory.", ) parser.add_argument( "--max-iterations", type=int, default=None, help="Maximum number of agent iterations (default: unlimited)", ) parser.add_argument( "--model", type=str, default=DEFAULT_MODEL, help=f"Claude model to use (default: {DEFAULT_MODEL})", ) return parser.parse_args() def main() -> None: """Main entry point.""" args = parse_args() # Check for auth: allow either API key or Claude Code auth token has_api_key = bool(os.environ.get("ANTHROPIC_API_KEY")) has_oauth_token = bool(os.environ.get("CLAUDE_CODE_OAUTH_TOKEN")) if not (has_api_key or has_oauth_token): print("Error: No Claude auth configured.") print("\nSet ONE of the following:") print(" # Standard API key from console.anthropic.com") print(" export ANTHROPIC_API_KEY='your-api-key-here'") print("\n # Or, your Claude Code auth token (from `claude setup-token`)") print(" export CLAUDE_CODE_OAUTH_TOKEN='your-claude-code-auth-token'") return # Automatically place projects in generations/ directory unless already specified project_dir = args.project_dir if not str(project_dir).startswith("generations/"): # Convert relative paths to be under generations/ if project_dir.is_absolute(): # If absolute path, use as-is pass else: # Prepend generations/ to relative paths project_dir = Path("generations") / project_dir # Run the agent try: asyncio.run( run_autonomous_agent( project_dir=project_dir, model=args.model, max_iterations=args.max_iterations, ) ) except KeyboardInterrupt: print("\n\nInterrupted by user") print("To resume, run the same command again") except Exception as e: print(f"\nFatal error: {e}") raise if __name__ == "__main__": main()