digraph linkcheck { graph [ goal="Build a Go CLI tool that crawls URLs, checks links for HTTP status, and reports broken links with robots.txt support", rankdir=LR, default_max_retries=3, retry_target="impl_setup", model_stylesheet=" * { model: gpt-5.2-codex;reasoning_effort: medium; } .hard { model: gpt-5.2-codex;reasoning_effort: high; } .verify { model: gpt-5.2-codex;reasoning_effort: medium; } .review { model: gpt-5.2-codex;reasoning_effort: high; } " ] start [shape=Mdiamond, label="Start"] exit [shape=Msquare, label="Exit"] // Phase 1: Requirements expansion expand_spec [ shape=box, timeout=600, prompt="Given the requirements: Build a Go CLI tool called 'linkcheck' that takes a URL as input, crawls the page, finds all links, checks each link for HTTP status, and outputs a report of broken links (4xx/5xx). It should respect robots.txt, have a configurable crawl depth (default 1), and output in both human-readable and JSON formats. Expand this into a detailed spec covering: - CLI interface (flags, arguments, usage) - Package structure (cmd/, pkg/) - Core types and interfaces (URL, Link, Report, etc.) - Robots.txt parsing and compliance - HTTP client configuration (timeouts, retries) - Crawl algorithm (depth limits, visited tracking) - Link extraction from HTML - Status code categorization (2xx=ok, 4xx/5xx=broken) - Output formats (human-readable table, JSON) - Error handling strategy - Test plan for each component Write the expanded spec to .ai/spec.md. Write status.json: outcome=succeeded" ] // Phase 2: Project setup impl_setup [ shape=box, timeout=600, max_retries=2, prompt="Read .ai/spec.md. Create the Go project structure: - go.mod (module name: linkcheck) - cmd/linkcheck/main.go (stub with basic CLI parsing) - pkg/crawler/ directory - pkg/robotstxt/ directory - pkg/checker/ directory - pkg/report/ directory Run: go build ./... Write status.json: outcome=succeeded if the project builds, outcome=failed with failure_reason otherwise." ] verify_setup [ shape=box, class="verify", timeout=300, prompt="Verify project setup. Run: 1. go build ./... 2. go vet ./... Check that: - go.mod exists with correct module name - cmd/linkcheck/main.go exists - pkg/ directories are created Write results to .ai/verify_setup.md. Write status.json: outcome=succeeded if all checks pass, outcome=failed with details otherwise." ] check_setup [shape=diamond, label="Setup OK?"] // Phase 3: Core types and interfaces impl_types [ shape=box, timeout=900, max_retries=2, prompt="Read .ai/spec.md. Implement core types and interfaces per the spec. Create pkg/crawler/types.go with: - URL type - Link type (URL, source, depth, status code) - CrawlConfig struct (max depth, user agent, timeout) - Crawler interface Create pkg/report/types.go with: - Report struct (total links, broken links, results slice) - LinkResult struct (URL, status, error) - Formatter interface Include comprehensive documentation for all exported types. Run: go build ./... Write status.json: outcome=succeeded if builds, outcome=failed with failure_reason otherwise." ] verify_types [ shape=box, class="verify", timeout=300, prompt="Verify core types implementation. Run: 1. go build ./... 2. go vet ./... Check that: - pkg/crawler/types.go defines all required types - pkg/report/types.go defines report types - All types have godoc comments - No compilation errors Write results to .ai/verify_types.md. Write status.json: outcome=succeeded if all pass, outcome=failed with details otherwise." ] check_types [shape=diamond, label="Types OK?"] // Phase 4: Robots.txt parser impl_robotstxt [ shape=box, class="hard", timeout=1200, max_retries=2, prompt="Read .ai/spec.md section on robots.txt compliance. Implement robots.txt parser in pkg/robotstxt/: - parser.go: Parse robots.txt files per RFC 9309 - matcher.go: Check if a URL is allowed for a given user-agent - cache.go: Cache parsed robots.txt files to avoid repeated fetches Handle: - User-agent matching (specific agent, wildcards, default *) - Allow/Disallow rules with path matching - Crawl-delay directive - Missing robots.txt (allow all) - Malformed robots.txt (be permissive) Create pkg/robotstxt/parser_test.go with tests for: - Various robots.txt formats - User-agent matching - Path matching edge cases Read: pkg/crawler/types.go for interfaces. Run: go test ./pkg/robotstxt/... Write status.json: outcome=succeeded if all tests pass, outcome=failed with failure_reason otherwise." ] verify_robotstxt [ shape=box, class="verify", timeout=300, prompt="Verify robots.txt parser implementation. Run: 1. go build ./... 2. go vet ./pkg/robotstxt/... 3. go test ./pkg/robotstxt/... -v Check test coverage: 4. go test ./pkg/robotstxt/... -cover Write results to .ai/verify_robotstxt.md. Write status.json: outcome=succeeded if all pass and coverage > 70%, outcome=failed with details otherwise." ] check_robotstxt [shape=diamond, label="Robots.txt OK?"] // Phase 5: HTTP checker impl_checker [ shape=box, timeout=1200, max_retries=2, prompt="Read .ai/spec.md section on HTTP checking. Implement HTTP link checker in pkg/checker/: - checker.go: Check URL status codes - Configure HTTP client with reasonable timeouts - Follow redirects (up to a limit) - Categorize status codes (2xx/3xx=ok, 4xx/5xx=broken) - Handle network errors gracefully - Support HEAD requests (fallback to GET if HEAD fails) Create pkg/checker/checker_test.go with: - Tests for various HTTP status codes - Mock HTTP server for testing - Timeout handling tests - Redirect handling tests Read: pkg/crawler/types.go for types. Run: go test ./pkg/checker/... Write status.json: outcome=succeeded if all tests pass, outcome=failed with failure_reason otherwise." ] verify_checker [ shape=box, class="verify", timeout=300, prompt="Verify HTTP checker implementation. Run: 1. go build ./... 2. go vet ./pkg/checker/... 3. go test ./pkg/checker/... -v Check: - Tests cover success, failure, and error cases - No race conditions: go test ./pkg/checker/... -race Write results to .ai/verify_checker.md. Write status.json: outcome=succeeded if all pass, outcome=failed with details otherwise." ] check_checker [shape=diamond, label="Checker OK?"] // Phase 6: HTML link extractor impl_extractor [ shape=box, timeout=1200, max_retries=2, prompt="Read .ai/spec.md section on link extraction. Implement HTML link extractor in pkg/crawler/: - extractor.go: Parse HTML and extract all links - Find links in , , ,