Skip to main content

Building an AI agent for campsite availability monitoring

·5 mins

If you’ve ever tried to book a campsite at a popular national park, you know the frustration. Sites disappear within seconds of becoming available. You refresh the page endlessly, hoping to catch that perfect spot.

But what if an AI agent could watch for availability changes, and recommend campsites before they vanish?

Why don’t we experiment with this idea?

Enter the AI agent approach #

Our agent doesn’t just detect changes - it analyzes them, understands their significance, and decides what action to take.

Here's the core agent loop:
def monitor_loop():
    while True:
        try:
            # 1. Fetch current availability from API
            current_state = fetch_availability(campground_id)

            # 2. Load previous state from JSON
            previous_state = load_state()

            # 3. Detect newly available sites
            new_availability = find_new_sites(current_state, previous_state)

            # 4. AI agent analyzes if availability is worth alerting about
            if new_availability:
                ai_analysis = agent.analyze_availability(new_availability, current_state)

                # 5. AI generates personalized email content
                if ai_analysis.should_alert:
                    email_content = agent.generate_alert_email(ai_analysis)
                    send_alert(email_content)

            # 6. Save current state
            save_state(current_state)

            # 7. Wait for next check
            time.sleep(check_interval)

        except Exception as e:
            log_error(e)
            time.sleep(300)  # Wait 5 minutes on error

The magic happens in steps 4 and 5. The agent doesn’t just check if sites are available - it analyzes whether they’re worth alerting about and generates personalized messages.

Building with Pydantic AI #

We chose Pydantic AI as our agent framework for its structured approach to LLM interactions. Instead of raw prompts and string parsing, we get type-safe data models and validated responses.

Agent setup with Pydantic AI
from pydantic_ai import Agent
from pydantic import BaseModel, Field

class AvailabilityAnalysis(BaseModel):
    should_alert: bool = Field(..., description="Whether this availability warrants an alert")
    urgency_level: str = Field(..., description="How quickly the user should act: low, medium, high")
    key_insights: List[str] = Field(..., description="Important observations about this availability")
    booking_advice: str = Field(..., description="Specific advice for booking these sites")

agent = Agent(
    "anthropic/claude-3-haiku",
    system_prompt="""You are a campsite availability expert who helps users secure hard-to-get camping spots.

    Analyze availability changes and determine if the change is significant enough to alert the user,
    how urgently they need to act, key insights about the availability (popular dates, site features),
    and specific booking advice.

    Consider factors like weekend vs weekday availability, holiday periods, number of consecutive
    nights available, and historical popularity of specific sites.
    """
)

This structured approach means the agent’s decisions are predictable and reliable. No parsing errors, no unexpected formats - just clean data we can act on.

Intelligent alert generation #

The second AI component generates the actual alert emails. Instead of templates with placeholders, each email is uniquely crafted based on the availability context.

Email generation with context
@agent.system_prompt
def email_generation_prompt():
    return """Generate concise, actionable email alerts for campsite availability.

    Lead with the most important information and explain why this availability matters.
    Provide specific booking recommendations with a clear call-to-action. Sound friendly
    and helpful, not robotic. Keep it under 5 sentences - users need to act fast.
    """

async def generate_alert_email(analysis: AvailabilityAnalysis, sites: List[Site]) -> EmailContent:
    result = await agent.run(
        f"Generate an email alert for these newly available sites: {sites}. "
        f"Analysis: {analysis.model_dump()}"
    )

    return EmailContent(
        subject=result.data.subject,
        body=result.data.body
    )

The agent crafts emails like: “Site 15A at Wawona just opened for Presidents Day weekend (Feb 14-16). This is one of the most requested weekends - I’d book within the next 30 minutes. Direct link: recreation.gov/camping/…”

No generic “New availability detected!” subject lines. Every alert is personalized and actionable.

The power of constraints #

We intentionally started with a tracer bullet - the thinnest possible slice that proves the concept. Just a single campground (Yosemite Wawona), a fixed 30-day window, email notifications only, and no user preferences or filtering.

These constraints let us focus on the core agent behavior. Does it make good decisions? Are the alerts helpful? Can it run reliably for days?

The architecture stays simple:

┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│   CLI Interface │────│  Agent Core     │────│  Notification   │
│   (Typer)       │    │  (Pydantic AI)  │    │  System (Email) │
└─────────────────┘    └─────────────────┘    └─────────────────┘
                              │
                       ┌─────────────────┐
                       │   Data Layer    │
                       │ (JSON/SQLite)   │
                       └─────────────────┘

It just wakes up, thinks, and acts.

State management and reliability #

The agent needs to remember what it’s seen before. We use simple JSON files for state persistence:

State tracking structure
# Availability state structure
{
    "campground_id": "232447",
    "last_check": "2024-01-15T14:30:00Z",
    "sites": {
        "site_001": {
            "available_dates": ["2024-02-01", "2024-02-02"],
            "site_name": "Site 1A"
        }
    }
}

Demo #

Want to see the agent in action? Check out this terminal recording showing the full workflow:

What makes this approach powerful #

Our agent is proactive and less reactive than traditional monitoring tools. It understands what matters and helps you act on it.

The AI components work together seamlessly. The analysis agent filters out noise to focus on meaningful availability, while the email agent translates that analysis into clear, actionable advice. Both adapt to the specific context of each availability change.

The agent approach means less noise, better alerts, and ultimately more successful bookings.

Building on the foundation #

Next iterations could add multiple campground monitoring with preference learning and historical pattern analysis for smarter predictions.

We could add more notification channels, like SMS alerts, for ultra-high priority availability.

Also, we can automate the booking as well if someone is interested in that.