This file provides guidance to AI Agents (like OpenAI's Codex, Cursor Agent, Claude Code, etc) when working with code in this repository.
The public README.md is the short, house-style introduction to the gem. The full north-star product contract — the exhaustive description of every capability, claim, and boundary that README.md used to be — now lives in docs/north-star-readme.md; read it before designing or changing any public behavior, and keep it updated when public behavior changes. The guides/ directory has the detailed integration guides. The product research corpus lives in docs/, which is deliberately git-ignored; read it if it is present locally, and never publish it.
This gem is part of a coherent ecosystem (railsfast, sessions, chats, moderate, organizations, pricing_plans, usage_credits, wallets, api_keys). Match the ecosystem conventions exactly: a single Clickwrap.configure do |config| … end block, has_*/verb-style class macros, adapter objects + no-op-default hook procs, string class names constantized lazily, adaptive install migrations, Minitest with a test/dummy app, SimpleCov, and the README/docs voice.
Clickwrap's value is evidence that is still true and still verifiable years after it was written. That makes a few ordinary habits actively dangerous here:
- Never overclaim in a public string. No public name, comment, error message, receipt field, task output, generated file, or documentation line may say or imply: compliant, GDPR compliant, enforceable, legally binding, court-proof, tamper-proof, audit approved, trusted time, qualified electronic signature, verified identity, physical location (for IP geolocation), that a person read or understood something, or anything that reads as legal advice. The gem provides evidence mechanics; the host application and its counsel own the legal text, lawful basis, substantive validity, capacity, authority, and retention periods.
- Distinguish source classes. In documentation, keep law, court decisions, regulator guidance, technical standards, vendor claims, pinned source-code observations, and product-design inferences visibly separate. Add an exact, direct URL for every external factual or legal claim, and pin source-code citations to immutable commits rather than moving branches.
- Released evidence formats are permanent. Every released receipt schema, canonicalization profile, digest field, event action, and lifecycle meaning gets a golden fixture, and new versions must keep verifying old receipts. A format change means a new explicit schema and verifier, never a silent reinterpretation. Do not edit a released migration underneath an installed application; add an upgrade migration.
- Required writes cannot be error-isolated. Evidence and the protected database action commit together or not at all. Optional after-commit hooks, analytics, and notifications are isolated and can never undo a committed action or stand in for one.
- The browser is not a policy author. Policy key, revision, document versions, validity, subject binding, retention, and request-evidence fields are resolved server-side and rechecked at submit. Never add a hidden field, parameter, or header that lets a client choose any of them.
- The host's privacy policy owns the why; the gem records the what, honestly. Clickwrap is nobody's nanny. Its job is evidence mechanics, not gatekeeping collection: it never refuses to record something because a developer did not write a sentence justifying it. Every
record_*flag still ships false, and the gem's own default is still record-nothing — but turning collection on is frictionless in every form.config.record_request_evidence_by_default = truerecords the coarse trio (IP address, browser user agent, country/region/city).record_ip_address,record_browser_user_agent, andrecord_ip_geolocationall take zero keyword arguments in a policy. Purposes,legal_basis_reference:, DPIA references, deletion clocks,trusted_proxy_configuration_digest, and thebecause:onkeep_recorded_*_indefinitely!anddeliberately_store_request_evidence_unencrypted!are ALL optional; gem-supplied honest defaults (Vocabulary::DEFAULT_REQUEST_EVIDENCE_PURPOSEand friends) fill every purpose field so no record ever carries a blank, and the privacy inventory marks each onegem_defaultorhostso the gem's sentence never passes for a reviewed one. What survives, and is not negotiable: never add a switch whose NAME hides what it collects (gdpr_compliant_mode,full_evidence,maximum_evidence,legal_proof); never overclaim (rule 1); never blurnot_configured/unavailable/recorded/deleted_after_retention; encryption stays on by default and= falsestill requires the nameddeliberately_store_request_evidence_unencrypted!call; scaffolding text (TODO) a host actually supplied is still rejected rather than recorded as a purpose; and a deletion clock declared alongside a keep-indefinitely for the same category is still refused as a contradiction. Owner directive, 2026-08-20 (v0.3.0), deliberately reversing the previous "every field needs a written purpose and a retention decision or boot fails" rule: the ceremony was pushing integrators to collect nothing, and no evidence is worse than un-reviewed evidence. Do not "fix" this back. - Names read aloud. Complete verb-and-noun names, positive booleans, destructive methods that say exactly what they delete,
ip_addressnotip,browser_user_agentnotua,ip_geolocationnotlocation,http_requestnotcontext,recorded_at_by_servernotsigned_at. If an example does not make sense read aloud by a developer who has never seen the gem, the name is wrong.
- Run
bundle exec rake testbefore claiming anything works, andbundle exec rubocopbefore committing. - Add tests in the same change. Fault injection, concurrency, replay, stale-token, disposition, and golden-receipt tests are load-bearing, not extras.
- Prefer explaining a refusal in a full sentence over raising a terse error. The policy compiler's job is to tell a developer what is wrong and what to do about it.
- Do not add a runtime dependency. Every integration is an optional adapter with a working no-op default.
- Do not publish, push, or create anything outside this repository without the owner asking for it.
Release-candidate record: the independent audit findings are resolved in the implementation and tracked in
docs/reviews/2026-08-15-production-release-checklist.md. The remaining remote-CI, downstream proof, unfamiliar-developer, legal/privacy, and publication gates are recorded there; do not collapse them into a generic “production ready” claim.