AGENTS.md

View Source

Guidance for AI agents working with SigilGuard.

Project Overview

SigilGuard is an Elixir library providing SIGIL Protocol integration for MCP security. It features a pluggable backend architecture with pure Elixir and Rust NIF backends.

Architecture

                      SigilGuard (Public API)
                              |
                    SigilGuard.Backend (Behaviour)
                              |
              +---------------+---------------+
              |                               |
              v                               v
SigilGuard.Backend.Elixir         SigilGuard.Backend.NIF
              |                               |
              v                               v
   OTP :crypto + Regex              Rustler + sigil-protocol

Backend Comparison

BackendIsolationLatencyStatusUse Case
ElixirFullMediumStableDefault, safe, works everywhere
NIFNoneLowestBetaProtocol parity, performance

Module Overview

SigilGuard (Main API)
    |
    +-- SigilGuard.Backend         Backend behaviour and selection
    |   +-- Backend.Elixir         Pure Elixir backend (default)
    |   +-- Backend.NIF            Rust NIF backend (optional)
    |
    +-- SigilGuard.Scanner         Sensitivity scanning engine
    +-- SigilGuard.Patterns        Pattern compilation and management
    +-- SigilGuard.Envelope        SIGIL envelope signing and verification
    +-- SigilGuard.Policy          Risk classification and trust gating
    +-- SigilGuard.Audit           Tamper-evident audit chain
    |   +-- Audit.Logger           Audit logger behaviour
    +-- SigilGuard.Identity        Trust level hierarchy
    +-- SigilGuard.Signer          Cryptographic signing behaviour
    |   +-- Signer.Ed25519         Ed25519 signer implementation
    +-- SigilGuard.Vault           Vault behaviour and utilities
    |   +-- Vault.InMemory         ETS-based in-memory vault
    +-- SigilGuard.Registry        SIGIL registry REST client
    |   +-- Registry.Cache         TTL cache for registry data
    +-- SigilGuard.Config          Configuration access
    +-- SigilGuard.Telemetry       Telemetry event definitions

Key Files

FilePurpose
lib/sigil_guard.exMain API module, dispatches to backend
lib/sigil_guard/backend.exBackend behaviour definition and selection
lib/sigil_guard/backend/elixir.exPure Elixir backend implementation
lib/sigil_guard/backend/nif.exNIF backend (Rustler)
lib/sigil_guard/scanner.exRegex-based sensitivity scanning
lib/sigil_guard/envelope.exSIGIL envelope sign/verify
lib/sigil_guard/policy.exRisk classification and trust gating
lib/sigil_guard/audit.exHMAC-SHA256 chain integrity
lib/sigil_guard/identity.exTrust level hierarchy
lib/sigil_guard/vault.exEncrypted storage behaviour
lib/sigil_guard/registry.exSIGIL registry REST client
lib/sigil_guard/config.exConfiguration access
lib/sigil_guard/telemetry.exTelemetry events and helpers
native/sigil_guard_nif/Rust NIF source code

Development Commands

mix setup                       # Install deps
mix test                        # Run tests (unit only)
mix test --include nif          # Run with NIF tests
mix lint                        # Format + Credo + Dialyzer
mix check                       # All quality checks
mix sobelow                     # Security analysis
mix docs                        # Generate docs
mix coveralls                   # Test coverage report
mix bench                       # Run benchmarks

Commit Conventions

All commits must follow the Conventional Commits specification. git_ops parses these to auto-generate CHANGELOG.md and determine version bumps.

Format: type(optional scope): description

Do not add Co-Authored-By or any AI/Claude attribution to commit messages.

TypeVersion bumpChangelog
feat:minor"Features"
fix:patch"Bug Fixes"
feat!: / fix!: / BREAKING CHANGE:majorshown
chore:, docs:, ci:, refactor:, style:, test:, build:nonehidden

Release Flow

  1. mix git_ops.release — updates changelog, bumps version in mix.exs and README.md, commits, and tags
  2. git push --follow-tags — pushes commit and tag
  3. CI (publish.yml) triggers on v* tag → runs checks → mix hex.publish

Testing

  • Unit tests - Run without Rust, test pure Elixir logic
  • NIF tests - Tagged @moduletag :nif, require Rust toolchain
  • Parity tests - Verify Elixir and NIF backends produce identical output

Test structure:

test/
+-- sigil_guard/
|   +-- scanner_test.exs       # Scanning tests
|   +-- envelope_test.exs      # Envelope sign/verify tests
|   +-- policy_test.exs        # Policy evaluation tests
|   +-- audit_test.exs         # Audit chain tests
|   +-- backend_test.exs       # Backend dispatch tests
|   +-- backend/
|       +-- elixir_test.exs    # Elixir backend tests
|       +-- nif_test.exs       # NIF backend tests
|       +-- parity_test.exs    # Cross-backend parity tests
+-- support/
    +-- test_signer.ex         # Deterministic test signer
    +-- nif_case.ex            # NIF test case template

Telemetry Events

EventMeasurementsMetadata
[:sigil_guard, :scan, :start]system_timepatterns_checked
[:sigil_guard, :scan, :stop]durationhit_count, patterns_checked
[:sigil_guard, :registry, :fetch, :start]system_timeurl
[:sigil_guard, :registry, :fetch, :stop]durationcount, source
[:sigil_guard, :policy, :decision]system_timeaction, risk_level, trust_level
[:sigil_guard, :audit, :logged]system_timeevent_type, actor

Configuration

config :sigil_guard,
  backend: :elixir,                        # :elixir | :nif
  registry_url: "https://registry.sigil-protocol.org",
  registry_ttl_ms: :timer.hours(1),
  registry_timeout_ms: 5_000,
  registry_enabled: false,
  scanner_patterns: :built_in

Backend Selection

# Check available backends
SigilGuard.Backend.available_backends()
#=> [:elixir] or [:elixir, :nif]

# Get current backend module
SigilGuard.Backend.impl()
#=> SigilGuard.Backend.Elixir

Common Patterns

Scanning and Redaction

{:ok, "safe text"} = SigilGuard.scan("safe text")
{:hit, hits} = SigilGuard.scan("AKIAIOSFODNN7EXAMPLE")
redacted = SigilGuard.scan_and_redact("key=AKIAIOSFODNN7EXAMPLE")

Envelope Signing

envelope = SigilGuard.Envelope.sign("did:sigil:abc", :allowed, signer: MySigner)
:ok = SigilGuard.Envelope.verify(envelope, public_key_b64u)

Policy Evaluation

:allowed = SigilGuard.policy_verdict("read_file", :authenticated)
:blocked = SigilGuard.policy_verdict("delete_database", :anonymous)

References