Files
royalroadupdates/AGENTS.md

5.2 KiB

Agent Instructions — royalroadupdates

Project Purpose

A small, self-contained Go CLI tool that checks RoyalRoad stories from a PocketBase bookmarks collection and reports their last-update times.

Repository Layout

.
├── cmd/royalroadupdates/     Entry point and integration tests
│   ├── main.go                 - CLI bootstrap, flag parsing (--json)
│   └── e2e_test.go             - End-to-end test: compiles binary, runs it,
│                                 asserts JSON shape and entry count
├── internal/
│   ├── pocketbase/
│   │   └── client.go            - Queries the public PocketBase collection endpoint.
│   │                             Accepts perPage and field params.
│   │                             Returns a list of structs with URL fields.
│   ├── royalroad/
│   │   └── scraper.go          - Given a URL, fetches the page, confirms it
│   │                             is a RoyalRoad fiction page, extracts the
│   │                             JSON-LD script block, parses name and
│   │                             dateModified into a struct.
│   │                             Returns zero-value + error for any failure
│   │                             so the caller can skip silently.
│   ├── formatter/
│   │   ├── table.go            - Renders []Story as a plain-text aligned
│   │   │                         table with relative-time "Last Update"
│   │   │                         column.
│   │   ├── json.go             - Renders []Story as JSON (used with --json).
│   │   └── relative.go         - Computes "X minutes/hours/days/months/years
│   │                             ago" strings from time.Time.
│   └── app.go                  - Orchestrates the full pipeline:
│                                   1. Load endpoint URL from compile-time var.
│                                   2. Query PocketBase for URLs.
│                                   3. Iterate URLs sequentially.
│                                   4. Collect valid RoyalRoad results.
│                                   5. Sort by dateModified descending.
│                                   6. Dispatch to appropriate formatter.
├── .env                        - Real endpoint URL (gitignored).
├── .env.example                - Template showing required env vars.
├── .gitignore                  - Must include .env and the built binary.
├── Makefile                    - All build, test, and check targets.
├── go.mod                      - Standard Go module file.
└── go.sum                      - Standard Go checksum file.

Code Style Rules

  • Formatting: All Go source files must pass gofmt. The make check target will reject any diff.
  • Imports: Group standard library first, then third-party (none expected), then local/internal. goimports ordering is acceptable.
  • Naming: Exported identifiers use PascalCase; unexported use camelCase. Acronyms like HTTP, URL, JSON keep all-caps when exported (FetchURL, ParseJSON).
  • Error handling: Always check errors explicitly. Do not swallow errors silently unless the design calls for silent skipping (RoyalRoad per-item failures). Return errors wrapped with fmt.Errorf("...: %w", err) for context.
  • Comments: Every exported type and function has a concise GoDoc comment. Internal helpers may omit comments if their purpose is obvious from the name.
  • No globals: Avoid package-level mutable state. Pass dependencies (HTTP client, configuration) as struct fields or constructor parameters.
  • HTTP client reuse: Create one http.Client with a configured timeout and share it across requests. Do not use http.DefaultClient unwrapped.

Build Rules

  • No local Go installation. Use make targets which wrap docker run --rm -v $(pwd):/src -w /src golang:1.22.
  • Endpoint injection: The Makefile reads .env and passes the value as -ldflags '-X main.PBURL=...'.
  • Output: The compiled binary is written to ./royalroadupdates in the repository root.
  • Targets:
    • make build — compile the binary.
    • make check — full quality loop (format, vet, test, e2e test).
    • make clean — remove the compiled binary.

Testing Rules

  • Unit tests: Cover pure helpers (e.g., relative.go, URL filtering logic) with table-driven tests. Use t.Parallel() where independent.
  • End-to-end test (e2e_test.go):
    • Uses the .env credentials and hits real services.
    • Compiles the binary via os/exec so it tests the actual build path.
    • Runs ./royalroadupdates --json.
    • Assertions:
      1. Exit code 0.
      2. Stderr is empty.
      3. Stdout is valid JSON.
      4. JSON is a non-empty array.
      5. Array contains at least 3 entries.
      6. Each entry has a non-empty name and a parseable date.
    • Since this test hits live services, it is inherently non-deterministic in data content but deterministic in shape. Treat network/Cloudflare flakiness as a signal to tune delays rather than a code defect.
  • Fix-and-rerun cycle: If make check fails at any step, fix the root cause and rerun make check until all gates pass.