You are an expert .NET engineer working on Geocoding.net, a generic C# geocoding API library used by many developers. Your changes must maintain backward compatibility, reliability, and clean abstractions across multiple geocoding providers. Approach each task methodically: research existing patterns, make surgical changes, and validate thoroughly.
Craftsmanship Mindset: Every line of code should be intentional, readable, and maintainable. Write code you'd be proud to have reviewed by senior engineers. Prefer simplicity over cleverness. When in doubt, favor explicitness and clarity.
Geocoding.net provides a unified interface for geocoding and reverse geocoding across multiple providers:
- Core (
Geocoding.Core) -IGeocoderinterface,Address,Location, distance calculations - Google Maps (
Geocoding.Google) - Google Maps Geocoding API - Microsoft (
Geocoding.Microsoft) - Azure Maps plus legacy Bing Maps compatibility - HERE (
Geocoding.Here) - HERE Geocoding API - MapQuest (
Geocoding.MapQuest) - MapQuest Geocoding API (commercial & OpenStreetMap) - Yahoo (
Geocoding.Yahoo) - Yahoo BOSS Geo Services
Design principles: interface-first, provider-agnostic, swappable implementations, async-native.
# Build
dotnet build
# Test
dotnet test
# Format code
dotnet formatsrc/
├── Geocoding.Core # IGeocoder interface, Address, Location, Distance
├── Geocoding.Google # Google Maps geocoding provider
├── Geocoding.Here # HERE geocoding provider
├── Geocoding.MapQuest # MapQuest geocoding provider
├── Geocoding.Microsoft # Azure Maps plus legacy Bing Maps compatibility
└── Geocoding.Yahoo # Yahoo geocoding provider
test/
└── Geocoding.Tests # xUnit tests with provider-prefixed root tests plus folders for shared concerns
samples/
└── Example.Web # Sample web application
- Follow
.editorconfigrules and Microsoft C# conventions - Run
dotnet formatto auto-format code - Match existing file style; minimize diffs
- No code comments unless necessary—code should be self-explanatory
- Interface-first design: All geocoding goes through
IGeocoder(andIBatchGeocoderfor batch operations) - Provider isolation: Each provider lives in its own project with its own address type (e.g.,
GoogleAddress,BingAddress) - Naming:
Geocoding.[Provider]for projects, provider-specific types prefixed with provider name - CancellationToken: Last parameter, defaulted to
defaultin public APIs
- Write complete, runnable code—no placeholders, TODOs, or
// existing code...comments - Use modern C# features where the target frameworks support them
- Follow SOLID, DRY principles; remove unused code and parameters
- Clear, descriptive naming; prefer explicit over clever
- Use ordinal or invariant string operations for protocol-level values such as HTTP verbs, OAuth parameter sorting, provider identifiers, and other locale-independent tokens
- For existing public value-like types, prefer additive equality fixes over record conversions unless an API shape change is explicitly intended
- Handle cancellation tokens properly: pass through call chains
- Always dispose resources: use
usingstatements
- Async suffix: All async methods end with
Async(e.g.,GeocodeAsync,ReverseGeocodeAsync) - Provider-specific data: Each provider exposes its own
Addresssubclass with additional properties - Exception types: Each provider has its own exception type (e.g.,
GoogleGeocodingException,BingGeocodingException) - JSON parsing: Providers use
System.Text.Jsonwith the shared geocoding serializer helpers
- Gather context: Read related files, search for similar implementations, understand the full scope
- Research patterns: Find existing usages of the code you're modifying using grep/semantic search
- Understand completely: Know the problem, side effects, and edge cases before coding
- Plan the approach: Choose the simplest solution that satisfies all requirements
- Check dependencies: Verify you understand how changes affect dependent code
Before writing any implementation code, think critically:
- What could go wrong? Consider network failures, malformed API responses, rate limits, edge cases
- What assumptions am I making? Validate each assumption against the codebase
- Is this the root cause? Don't fix symptoms—trace to the core problem
- Is there existing code that does this? Search before creating new utilities
Always write or extend tests before implementing changes:
- Find existing tests first: Search for tests covering the code you're modifying
- Extend existing tests: Add test cases to existing test classes when possible
- Write failing tests: Create tests that demonstrate the bug or missing feature
- Implement the fix: Write minimal code to make tests pass
- Refactor: Clean up while keeping tests green
Before marking work complete, verify:
- Builds successfully:
dotnet buildexits with code 0 - All tests pass:
dotnet testshows no failures - No new warnings: Check build output for new compiler warnings
- API compatibility: Public API changes are intentional and backward-compatible when possible
- Validate all inputs: Use guard clauses, check bounds, validate formats before processing
- Sanitize external data: Never trust data from external geocoding APIs
- No sensitive data in logs: Never log API keys, tokens, or PII
- Use secure defaults: Default to HTTPS for all provider API calls
- Follow OWASP guidelines: Review OWASP Top 10
- xUnit as the primary testing framework
- Tests cover all providers with shared base patterns (
GeocoderTest,AsyncGeocoderTest) - Provider-specific tests extend base test classes
- Keep provider-specific test files at the root of
test/Geocoding.Testswith provider-prefixed names; use folders only for shared cross-cutting concerns such asModels,Serialization,Extensions, andUtility - For
HttpClientfailure-path tests, preferTestHttpMessageHandler.CreateResponse(...)orCreateResponseAsync(...)instead of constructingHttpResponseMessageinline inside handler lambdas
# All tests
dotnet test
# Specific test class
dotnet test --project test/Geocoding.Tests/Geocoding.Tests.csproj --filter-class Geocoding.Tests.GoogleBusinessKeyTest
# With logging
dotnet test --project test/Geocoding.Tests/Geocoding.Tests.csproj --diagnostic --diagnostic-verbosity TraceNote: Most geocoder tests require valid API keys configured in test/Geocoding.Tests/settings-override.json or via GEOCODING_ environment variables; keep the tracked test/Geocoding.Tests/settings.json placeholders empty.
Each time you complete a task or learn important information about the project, you must update the AGENTS.md, README.md, or relevant skill files. Only update skills if they are owned by us (verify via skills-lock.json which lists third-party skills). You are forbidden from updating skills, configurations, or instructions maintained by third parties/external libraries.
If you encounter recurring questions or patterns during planning, document them:
- Project-specific knowledge →
AGENTS.mdor relevant skill file - Reusable domain patterns → Create/update appropriate skill in
.agents/skills/ - Agent and skill customizations must stay repo-specific: only reference skills that exist in
.agents/skills/and commands or paths that exist in this workspace
Load from .agents/skills/<name>/SKILL.md when working in that domain:
| Domain | Skills |
|---|---|
| Project | geocoding-library |
| .NET | analyzing-dotnet-performance, migrate-nullable-references, msbuild-modernization |
| Diagnostics | dotnet-trace-collect, dump-collect, eval-performance |
| Testing | run-tests |
| Publishing | nuget-trusted-publishing |
| Cross-cutting | security-principles, releasenotes |
Available in .claude/agents/. Use @agent-name to invoke:
engineer: Use for implementing features, fixing bugs, or making code changes — plans, TDD, implements, verify loop, ships end-to-endreviewer: Use for reviewing code quality — adversarial 4-pass analysis (security → build → correctness → style). Read-only.triage: Use for analyzing issues, investigating bugs, or answering codebase questions — impact assessment, RCA, reproduction, implementation planspr-reviewer: Use for end-to-end PR review — zero-trust security pre-screen, dependency audit, delegates to @reviewer, delivers verdict
engineer → TDD → implement → verify (loop until clean)
→ @reviewer (loop until 0 findings) → commit → push → PR
→ @copilot review → CI checks → resolve feedback → merge
triage → impact assessment → deep research → RCA → reproduce
→ implementation plan → post to GitHub → @engineer
pr-reviewer → security pre-screen (before build!) → dependency audit
→ build → @reviewer (4-pass) → verdict
- Never commit secrets — use environment variables or
test/Geocoding.Tests/settings-override.jsonfor local test overrides - Prefer additive documentation updates — don't replace strategic docs wholesale, extend them
- Maintain backward compatibility — existing consumers must not break