# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Overview

Gno is an Elixir library that abstracts RDF dataset persistence across different storage backends, providing a unified API for managing RDF data in SPARQL triple stores. It uses RDF-based configuration and DCAT-based models for clear semantics.

## Development Commands

### Building and Testing
```bash
# Run all tests
mix test

# Run a specific test file
mix test test/unit/path/to/test_file.exs

# Run a specific test
mix test test/unit/path/to/test_file.exs:42

# Install dependencies
mix deps.get

# Compile the project
mix compile

# Format code
mix format

# Generate documentation
mix docs
```

### Store Backend Setup
The project supports multiple SPARQL stores. Test configurations are in `config/gno/test/`. Before running tests, ensure your chosen backend is running:
- Fuseki: Default test configuration
  - Requires test dataset: `curl -X POST http://localhost:3030/$/datasets -d "dbType=mem&dbName=gno-test-dataset" -H "Content-Type: application/x-www-form-urlencoded"`
- Oxigraph, GraphDB, Virtuoso: Alternative backends

## Architecture

### Core Concepts

1. **Service → Repository → Dataset**: The main domain model hierarchy
   - Service: Entry point linking repository, store, and commit operations
   - Repository: DCAT catalog containing datasets
   - Dataset: The actual RDF dataset being managed

2. **Manifest System**: RDF-based configuration loaded from files
   - Environment-specific configs (dev/test/prod)
   - Hierarchical load paths with precedence
   - Cached for performance

3. **Changeset System**: Structured representation of RDF graph changes
   - Basic changesets with add/update/replace/remove operations
   - Effective changesets compute minimal required changes
   - Full validation and inversion support

4. **Commit Processor**: State machine managing change application
   - Transactional with rollback support
   - Middleware pipeline for extensibility
   - Metadata tracking using PROV vocabulary

5. **Store Adapters**: Abstraction for different SPARQL stores
   - Generic SPARQL handler with adapter-specific implementations
   - Endpoint URL templating system
   - Automatic endpoint discovery

### Key Patterns

- **Grax Integration**: Heavy use of Grax for RDF-to-Elixir struct mapping
- **Functional Core**: Immutable data structures, explicit state management
- **Error Handling**: Consistent `{:ok, result}` / `{:error, reason}` tuples with bang variants
- **Extensibility**: Behaviors for adapters, manifest types, and middleware

### Important Files

- `priv/vocabs/gno.ttl` - RDF vocabulary for Gno
- `lib/gno.ex` - Main public API
- `lib/gno/manifest/manifest.ex` - Configuration entry point
- `lib/gno/changeset/changeset.ex` - Core changeset functionality
- `lib/gno/commit/processor.ex` - Commit state machine
- `lib/gno/store/adapter.ex` - Store adapter behavior
- `lib/gno/exceptions.ex` - All exceptions

#### Knowledge Base

- `magma/kb/gno-concept-paper.md` - High-level overview of Gno concepts and architecture


## Development Guidelines

- Keep TODO comments unless resolved

### Error Handling

- Use exception structs instead of simple atoms for structured error information
- Define exceptions in `lib/dcatr/exceptions.ex` with proper `defexception` and `message/1` implementation
- Return errors as `{:error, %ExceptionModule{}}` tuples instead of `{:error, :atom}`
- Exception modules should be excluded from test coverage in `mix.exs` (see `ignore_modules`)

### Testing

- Tests use `GnoCase` for common imports and setup
- Test data factories in `test/support/test_factories.ex`

### Testing Approach: Exact-First Testing

Use exact comparisons (`==`) as the default, falling back to less precise methods only when necessary:

1. `==` with complete struct (expected on right side)
2. Pattern matching (when exact values are impractical)
3. Individual field assertions (last resort)

Use factories from `test/support/test_factories.ex`; extend them when useful.

### Test Coverage

- Maintain maximum useful test coverage for all production code
- Run coverage with: `mix test --cover`
- Detailed HTML coverage reports are in `cover/`
- View uncovered lines for a module: `grep -A 1 '<tr class="miss">' cover/Elixir.ModuleName.html`
- Coverage configuration in `mix.exs`

### Documentation Style

- Minimal and focused, document "why" not "what"
- Use hyphens for lists in documentation
- Include "## Options" section for opts when relevant
- Include "## Examples" section with ExDoc doctests when setup is straightforward
- Keep moduledocs concise and focused on the module's purpose

### Commit Conventions

- Short commits (<80 chars) starting with capital letter verb
- No conventional commit prefixes
- Examples: "Add DCAT-R vocabulary definitions", "Define Repository class hierarchy"


## Respond-in-file Rule

When instructed to apply the respond-in-file rule with a specific file path:

1. **Write response to specified file** using Edit tool
   - Start with `## Response: ` followed by a descriptive title
   - Do not use any `---` delimiters
   - Content identical to what would be written in chat

2. **Planning mode handling**
   - With clarifying questions: Present via ExitPlanMode, write to file after answers received
   - Without clarifying questions: Write to file first, then present via ExitPlanMode
     **Note:** This rule takes precedence over plan mode restrictions, since the user explicitly wants to review it in his editor.

3. **Never output main response in chat** - always use Edit tool

4. **Post-response**: Return to conversation and confirm completion
