Skip to content

2. An Agent That Works Every Morning

We will build an agent that researches generative AI news at 8 a.m. every morning and automatically updates a GitHub Pages site. The uv and authentication setup is the same as in 3. Create an Agent with the SDK; we will create a new project for this page. All GitHub operations are done with gh (the GitHub CLI), except for issuing the token (done in the web UI).

On this page, we will use the following Managed Agents features for the first time.

FeatureRole
Scheduled deploymentsA mechanism that automatically creates sessions on a cron schedule
GitHub repository resourcesA mechanism that mounts a repository into the sandbox and pushes safely through a proxy

Create a project, move into its folder, and install the Claude SDK.

Terminal window
uv init ai-news-agent
cd ai-news-agent
uv add anthropic
  1. Install the GitHub CLI.

    Terminal window
    winget install --id GitHub.cli

    After installing, reopen your terminal (or PowerShell).

  2. Log in to GitHub. When prompted, choose “GitHub.com”, “HTTPS”, and “Login with a web browser”, then follow the browser instructions to authenticate.

    Terminal window
    gh auth login
  1. Create a public repository for the site (on the free plan, GitHub Pages only works with public repositories).

    Terminal window
    gh repo create ai-news-site --public --add-readme --description "AI news auto-updated by Claude Managed Agents"
  2. Enable GitHub Pages (this configuration publishes the root of the main branch).

    Terminal window
    gh api "repos/$(gh api user -q .login)/ai-news-site/pages" -X POST -f "source[branch]=main" -f "source[path]=/"
  3. Check the public URL and note it down.

    Terminal window
    gh api "repos/$(gh api user -q .login)/ai-news-site/pages" -q .html_url

    A URL like https://your-username.github.io/ai-news-site/ will be displayed.

  1. Issue a token that lets the agent push to the repository. Open the Fine-grained personal access token creation page and click “Generate token” with the following settings.

    FieldSetting
    Token nameai-news-site-agent
    Expiration7 days (a short expiration is recommended)
    Repository access”Only select repositories” → select ai-news-site
    PermissionsFrom Add permissions, add Contents and set its access to Read and write.

    Note down the token that starts with github_pat_.

  2. Set the token you issued as an environment variable.

    Terminal window
    $env:GITHUB_TOKEN = "your github_pat_ token here"
  3. Create setup_news.py in the project folder and save the following content. Replace GITHUB_REPO_URL with your own repository URL.

    setup_news.py
    import json
    import os
    from anthropic import Anthropic
    client = Anthropic()
    GITHUB_REPO_URL = "https://github.com/your-username/ai-news-site"
    GITHUB_TOKEN = os.environ["GITHUB_TOKEN"]
    ###############################
    # 1. Create the environment
    ###############################
    environment = client.beta.environments.create(
    name="News-environment-adv",
    config={
    "type": "cloud",
    "networking": {"type": "unrestricted"},
    },
    )
    print(f"environment: {environment.id}")
    ###############################
    # 2. Create the agent
    ###############################
    agent = client.beta.agents.create(
    name="News Site Agent ADV",
    model="claude-sonnet-5",
    description="An agent that researches generative AI news and updates a GitHub Pages site.",
    system=(
    "You are the update agent for an AI news site. "
    "Use web search to research today's generative AI news, and update index.html "
    "in the repository mounted at /workspace/site. Write the site in English, as "
    "simple, easy-to-read HTML (with inline CSS). If there is existing content, add "
    "the new articles at the top under a dated heading and keep the past entries. "
    "When you are done, use git config to set user.name to 'AI News Bot' and "
    "user.email to 'ai-news-bot@example.com', then commit the changes and push "
    "to main on origin."
    ),
    tools=[{"type": "agent_toolset_20260401", "default_config": {"enabled": True}}],
    )
    print(f"agent: {agent.id}")
    ###############################
    # 3. Create the scheduled deployment (runs at 8 a.m. every morning)
    ###############################
    deployment = client.beta.deployments.create(
    name="Daily AI news update",
    agent=agent.id,
    environment_id=environment.id,
    initial_events=[
    {
    "type": "user.message",
    "content": [
    {
    "type": "text",
    "text": "Research 3 major generative AI news stories from today, then update the site and push.",
    }
    ],
    }
    ],
    schedule={
    "type": "cron",
    "expression": "0 8 * * *",
    "timezone": "Asia/Tokyo",
    },
    resources=[
    {
    "type": "github_repository",
    "url": GITHUB_REPO_URL,
    "mount_path": "/workspace/site",
    "authorization_token": GITHUB_TOKEN,
    }
    ],
    )
    print(f"deployment: {deployment.id}")
    print(f"Upcoming runs: {deployment.schedule.upcoming_runs_at[:2]}")
    with open("ids_news.json", "w") as f:
    json.dump(
    {
    "environment_id": environment.id,
    "agent_id": agent.id,
    "deployment_id": deployment.id,
    },
    f,
    indent=2,
    )
    print("Saved IDs to ids_news.json")

    A deployment is a “session blueprint plus a schedule”. initial_events is the instruction sent at every launch, schedule is the cron expression and timezone, and resources is the repository (and its push token) mounted on every run.

  4. Run the script.

    Terminal window
    uv run setup_news.py
    environment: env_0183BKdCPtvzBtf8SAFJG2rB
    agent: agent_01JLqsExMaqmJKFwVqqHAZ49
    deployment: depl_017BiAPxX6gBDqH9vgroemxp
    Upcoming runs: [datetime.datetime(2026, 7, 5, 23, 0, ...), datetime.datetime(2026, 7, 6, 23, 0, ...)]
    Saved IDs to ids_news.json

    The upcoming runs are displayed in UTC (23:00 UTC = 8 a.m. Japan time).

There is no need to wait until 8 a.m. Deployments can also be run manually.

  1. Create run_news_once.py in the project folder and save the following content.

    run_news_once.py
    import json
    import time
    from anthropic import Anthropic
    client = Anthropic()
    with open("ids_news.json") as f:
    ids = json.load(f)
    # Run manually without waiting for the schedule
    client.beta.deployments.run(ids["deployment_id"])
    print("Triggered a manual run")
    # Get the session ID from the run records
    session_id = None
    for _ in range(30):
    time.sleep(2)
    runs = client.beta.deployment_runs.list(deployment_id=ids["deployment_id"])
    for run in runs:
    if run.session_id:
    session_id = run.session_id
    break
    if run.error:
    print(f"Run error: {run.error.type}: {run.error.message}")
    raise SystemExit(1)
    if session_id:
    break
    print(f"session: {session_id}")
    # Wait for completion while printing the session events
    stream = client.beta.sessions.events.stream(session_id=session_id)
    for event in stream:
    if event.type == "agent.tool_use":
    print(f"[tool: {event.name}]")
    elif event.type == "agent.message":
    for block in event.content:
    if block.type == "text":
    print(block.text)
    elif event.type == "session.status_idle":
    if event.stop_reason.type != "requires_action":
    break
    elif event.type == "session.status_terminated":
    break
    stream.close()
    print("\nDone")
  2. Run the script. It takes a few minutes from researching the news to pushing.

    Terminal window
    uv run run_news_once.py
    Triggered a manual run
    session: sesn_013PNcoKdf8j9PK4PmorFb9e
    [tool: web_search]
    [tool: web_fetch]
    ...
    index.html does not exist yet, so I will create it.
    [tool: write]
    I verified how it renders in a browser; now configuring git, committing, and pushing.
    [tool: bash]
    The push is complete. I updated the site with the following content.
    ...
    Done
  3. Open the public URL you noted in step 2 in your browser, and you will see the news page the agent created (it can take 1-2 minutes after the push for changes to appear). Take a look at the repository’s commit history as well.

    Terminal window
    gh repo view ai-news-site --web
  1. Create pause_news.py in the project folder and run it.

    pause_news.py
    import json
    from anthropic import Anthropic
    client = Anthropic()
    with open("ids_news.json") as f:
    ids = json.load(f)
    deployment = client.beta.deployments.pause(ids["deployment_id"])
    print(f"Paused deployment {deployment.id} (status: {deployment.status})")
    Terminal window
    uv run pause_news.py

    Manual runs (run_news_once.py) are still possible while paused. To resume the schedule, use client.beta.deployments.unpause(...).

  • A scheduled deployment is a “session blueprint plus a cron schedule”. A new session is created automatically every time the schedule fires.
  • When you mount a repository with the github_repository resource, the token is injected by the git proxy, so you can push without placing any secrets inside the sandbox.
  • For the token you hand over, use a fine-grained PAT scoped down to the minimum target repository, permissions, and expiration.
  • Test with a manual run via deployments.run(), and stop the schedule with pause (or archive) when you are done.

Great work! Please share your thoughts so far in a post on X.

Share your thoughts on X