Building with Claude Code on a Phone: An iNaturalist Observation Viewer in Practice

Simon Willison built a zero-ops iNaturalist data viewer using only a phone and Claude Code
During a camping trip, Simon Willison built a web tool displaying iNaturalist nature observations entirely on his phone using Claude Code. The project uses a three-layer architecture: a Python CLI tool for spatiotemporal clustering, Git Scraping for automated data pipelines, and a single AI prompt to generate the frontend page—all hosted on GitHub for zero-ops maintenance. This case demonstrates how AI-assisted programming reduces hardware dependency and showcases a lightweight development paradigm combining Git Scraping, static JSON, and AI-generated frontends.
Overview
Simon Willison (renowned developer and creator of Datasette) built a web tool for displaying iNaturalist nature observation records entirely using his phone and Claude Code during a camping trip. This project demonstrates the practicality of AI-assisted programming on mobile devices while providing an architectural reference for chaining multiple simple components into a complete data pipeline.
Simon Willison is a veteran figure in the Python web development world. He's one of the co-creators of the Django framework and later built Datasette—an open-source tool that instantly transforms SQLite databases into interactive APIs and data browsing interfaces. Datasette's design philosophy is "make publishing data as simple as publishing a webpage," and this obsession with lightweight data tools runs through much of his recent work. He's also one of the most active practitioners and documenters in the AI-assisted programming space, continuously sharing experiences and methodologies for using large language models in software development on his personal blog.
Project Background: Why Code on a Phone?
Simon has two separate accounts on iNaturalist, and he wanted to display observations from both accounts grouped by time on a single page. iNaturalist is a global citizen science platform jointly operated by the California Academy of Sciences and the National Geographic Society, where users can upload photos of wildlife they observe in the field. The platform uses community collaboration and AI image recognition to help identify species. To date, it has accumulated over 200 million observation records covering more than 400,000 species, making it one of the world's largest open biodiversity data sources. iNaturalist provides a comprehensive RESTful API that allows developers to query observation data by user, geographic region, taxonomic classification, and other dimensions—this forms the data foundation for Simon's project.
The traditional approach would require sitting at a computer for several hours writing code, but he chose a lighter path—completing the entire development workflow on his phone with Claude Code while camping.
Claude Code is a command-line AI programming tool from Anthropic that runs directly in a terminal environment. It can read project files, understand code context, execute shell commands, and autonomously write and modify code. Unlike traditional IDE plugin-style AI assistants, Claude Code's pure terminal interaction mode means it has no dependency on graphical interfaces—which is precisely what allows it to run smoothly in phone terminal apps (such as Termux or via SSH connections to remote development machines). Developers only need to describe requirements in natural language, and Claude Code can complete the full development cycle from creating files and writing code to running tests.
This choice itself illustrates a trend: with AI programming assistants, developers are no longer tethered to workstations equipped with large screens and keyboards.
Technical Architecture Breakdown: Three-Layer Component Design
Layer 1: Python CLI Tool for Data Aggregation
Simon first built a Python command-line tool called inaturalist-clumper, responsible for fetching and "clumping" observation records. The core logic groups observations that are within 2 hours of each other in time and 5 kilometers of each other in geographic distance into a single clump.
This aggregation strategy is highly practical—it essentially represents the concept of "one outing" and better reflects actual usage patterns than simple date-based grouping. From a technical perspective, this is a simplified implementation of spatiotemporal clustering. Classic spatiotemporal clustering algorithms like ST-DBSCAN need to simultaneously define "proximity" relationships in both time and space dimensions, resulting in higher computational complexity. Simon's approach uses a more intuitive greedy strategy: after sorting by time, it sequentially checks the time difference and geographic distance between each new record and the last record in the current group. If both are within threshold, the record joins the current group; otherwise, a new group begins. The choice of 2-hour and 5-kilometer thresholds reflects a reasonable physical assumption—during a single outdoor observation activity, a person typically won't wait more than 2 hours between recording species, nor travel more than 5 kilometers in a single session. While this heuristic isn't as rigorous as formal clustering algorithms, it's accurate enough for personal data display scenarios.
Layer 2: Git Scraping for Automated Data Pipeline
The second step is setting up the simonw/inaturalist-clumps repository, leveraging Simon's own "Git Scraping" pattern—using GitHub Actions to periodically run the CLI tool, save results as a clumps.json file, and commit it to the repository.
Git Scraping is a data collection pattern that Simon Willison proposed and actively promoted in 2020. Its core idea is extremely simple: use GitHub Actions' scheduled task functionality (cron scheduling) to periodically run a script that fetches the latest state from a data source, then commit the results as a file to a Git repository. Since Git naturally records the diff of each commit, the repository automatically becomes a data archive with complete version history. Compared to traditional scraper + database solutions, Git Scraping requires no server or database instance maintenance. All data is stored as plain text files on GitHub, inherently providing version control, collaborative editing, and public access capabilities. This pattern has been widely adopted for tracking government data changes, monitoring website price fluctuations, recording API responses, and more—with hundreds of public repositories on GitHub based on this approach.
This design has several elegant aspects:
-
Native cross-origin access support: JSON files hosted on GitHub come with CORS support, allowing frontends to fetch directly. CORS (Cross-Origin Resource Sharing) is a browser security mechanism that by default only allows JavaScript on a webpage to request resources from the same origin (same protocol, domain, and port). If a frontend page is hosted on
example.comand wants to usefetch()to request data fromapi.another.com, the server must include anAccess-Control-Allow-Originheader in the response to explicitly authorize it. GitHub's Raw file service (raw.githubusercontent.com) sets a permissive CORS policy in its response headers by default, meaning frontend pages on any domain can directly request files from GitHub repositories without setting up a proxy server to relay requests—a huge convenience for purely frontend static applications. -
Free scheduled tasks: GitHub Actions provides free cron scheduling capability. GitHub Actions is GitHub's built-in CI/CD and automation platform, completely free for public repositories and offering 2,000 minutes of free execution time per month for private repositories. Developers can define YAML-formatted workflow files in the
.github/workflows/directory of a repository, using thescheduletrigger with cron expressions for timed execution. For example,cron: '0 */6 * * *'means running every 6 hours. It's worth noting that GitHub Actions' cron scheduling doesn't guarantee second-precise execution times—during high platform load, there may be delays of several minutes to tens of minutes—but this is perfectly adequate for data collection scenarios that don't require high timeliness. -
Built-in audit trail: Git commit history automatically records every data change
For personal projects and small data pipelines, Git Scraping is a near-zero-cost automation solution.
Layer 3: AI One-Click Frontend Page Generation
The final step is the frontend page. Simon provided Claude Code with a precise prompt requesting an HTML application with specific requirements:
- Fetch JSON data from a GitHub Raw URL
- Display all observation records using iNaturalist's small.jpg thumbnails
- Use
loading=lazyfor image lazy loading to optimize page performance - Show a larger image in an HTML modal when thumbnails are clicked
- Display both common and species names
loading="lazy" is an HTML-native image lazy loading attribute, first implemented in Chrome 76 in 2019 and now supported by all major browsers. It works by having the browser not immediately load images with loading="lazy" set during page parsing, instead waiting until the image is about to enter the viewport before initiating the network request. For a page like Simon's project that might contain hundreds of nature observation photos, lazy loading significantly reduces initial page load time and bandwidth consumption—when users open the page, only the few images visible on screen need to load, rather than downloading all image resources at once. Previously, achieving similar effects required relying on the Intersection Observer API or third-party JavaScript libraries, but the introduction of the native attribute turned this optimization into something achievable with a single HTML attribute.
The entire frontend page was generated with a single prompt, requiring no additional manual adjustments.
Three Design Principles Worth Adopting
AI Programming on a Phone: Decentralizing Development Environments
The most noteworthy aspect of this case is that the entire project was completed on a phone using Claude Code. AI programming assistants are reducing development's hardware requirements—you can produce usable software during your commute, at a coffee shop, or even at a campsite.
This isn't to say phones will replace computers as primary development tools, but rather that for lightweight projects and rapid prototyping, mobile + AI is already a viable combination.
Zero-Ops Serverless Architecture
The entire architecture requires no self-hosted servers:
| Function | Provider |
|---|---|
| Data fetching and processing | GitHub Actions |
| Data storage | GitHub repository (JSON files) |
| Frontend hosting | GitHub Pages |
| CDN distribution | GitHub Raw file service |
Maintenance costs are virtually zero, with no worries about server downtime or billing overages. For personal projects, this "everything hosted on GitHub" architecture is extremely low-maintenance.
It's worth noting that this architecture pattern can be seen as an extremely simplified implementation of the "Serverless" philosophy. Traditional Serverless architectures typically rely on cloud function platforms like AWS Lambda or Cloudflare Workers, still requiring trigger configuration, environment variable management, and cold start handling. Simon's approach uses the GitHub platform itself as a complete Serverless infrastructure: Actions serve as the compute layer, repositories as the storage layer, and Pages as the distribution layer. The limitations of this approach are also clear—it's only suitable for scenarios with small data volumes (GitHub recommends single files under 100MB), low update frequencies (Actions' cron minimum interval is about 5 minutes with actual execution delays), and read-only display scenarios that don't require user write operations. But within these constraints, it's virtually the lowest-cost, lowest-maintenance-burden solution available.
Prompts as Technical Specifications
The prompt Simon shared is itself a clear technical specification document, containing the data source URL, UI interaction logic, performance optimization strategies, and feature requirements. This pattern of "one prompt generates a complete functional page" is particularly effective for lightweight data display tools.
The key lies in prompt quality: the more explicit the requirements and the clearer the boundaries, the closer the AI-generated code will be to expectations. This is actually consistent with the concept of a "Software Requirements Specification" (SRS) in software engineering—the difference being that traditional SRS documents are written for human developers, while today's prompts are written for AI. Excellent prompts and excellent requirements documents share the same qualities: clear input/output definitions, specific technical constraints, precise interaction behavior descriptions, and anticipation of edge cases. The reason Simon's prompt could generate a usable page in one shot is precisely because, as a seasoned developer, he could precisely translate the technical solution in his mind into structured natural language descriptions.
Conclusion
This project isn't large in scope, but it clearly demonstrates a practical lightweight development approach: Git Scraping for automated data collection + static JSON storage + AI-generated frontend pages.
For developers with similar data display needs, this combination is worth trying: no backend server needed, no database needed, no complex deployment process needed, and you don't even need a computer—a phone plus Claude Code is enough.
Related articles
Product ReviewsThe Programmer's Desk Setup Guide: Building a Workspace That Feels Like Home
Discover how programmers build productive, comfortable workspaces. From multi-monitor setups to ergonomic design, explore the desk philosophy that drives focus and flow.
Product ReviewsQoder vs Cursor Real-World Comparison: Which $20/Month AI IDE Is Better?
Hands-on comparison of Qoder vs Cursor AI IDEs: Agent autonomy, human interaction count, and architecture decisions. Qoder needed only 2 interactions vs Cursor's 8.
Product ReviewsCursor Cloud Agent Demo: Eliminating Bottlenecks Across the Entire Software Development Lifecycle
Deep analysis of Cursor's Cloud Agent demo showing how cloud VMs, automated test artifacts, and a full-chain control plane systematically eliminate human bottlenecks across the software development lifecycle.