Skip to main content

Contributing to Lucid Layer

Thank you for your interest in contributing to Lucid — the autonomous AI infrastructure layer. Whether you’re fixing a bug, adding a feature, improving docs, or writing tests, your contribution matters.

Table of Contents


Getting Started

Prerequisites


Development Workflow


Project Structure

Critical dependency rule:
  • gateway-lite may import from engine
  • engine must NEVER import from gateway-lite (ESLint-enforced)

Code Standards

TypeScript

  • Strict mode — all new code must compile under strict: true
  • No any — use proper types. unknown + type guards when truly dynamic.
  • No import type in test files — babel/jest doesn’t support it. Use regular import.
  • Feature-domain organization — code lives in its domain folder (memory, payment, deployment), not grouped by technical layer
  • Interface-first — new features should define an I* interface, then implement (e.g., IDeploymentStorePostgresDeploymentStore + InMemoryDeploymentStore)
  • Factory pattern — use getXxx() singletons with resetXxx() for test teardown

Naming

What NOT to do

  • Don’t add comments to code you didn’t change
  • Don’t add error handling for scenarios that can’t happen
  • Don’t create abstractions for one-time operations
  • Don’t add backward-compatibility shims — just change the code
  • Don’t introduce circular dependencies between packages

Commit Conventions

Follow Conventional Commits:

Types

Scopes

Use the domain: memory, deployment, payment, receipt, epoch, identity, anchoring, reputation, compute, db.

Examples


Testing

Running tests

Writing tests

  • Every new feature needs tests. No exceptions.
  • Use InMemory* stores for unit tests (fast, deterministic)
  • Mock external dependencies — deployers, providers, LLMs
  • Follow existing patterns — look at nearby __tests__/ folders
  • Test the contract, not the implementation — test via the interface, not internal methods

Test structure

Each domain has its own __tests__/ folder next to the source code.

Working with Solana Programs

Program layout

Each program lives in programs/<name>/src/lib.rs with Anchor macros. PDAs follow the pattern ["seed", key.as_ref()].

Working with EVM Contracts

17 contracts in contracts/src/ — full parity with Solana programs where applicable.

Working with the Offchain Engine

Adding a new feature

  1. Define the interface in engine/src/<domain>/
  2. Implement InMemory (tests) + Postgres (production) versions
  3. Add factory in index.ts with getXxx() / resetXxx()
  4. Write tests in __tests__/ using the InMemory implementation
  5. Add routes in gateway-lite/src/routes/ (thin handlers, delegate to engine)
  6. Update OpenAPI in openapi.yaml

Key patterns to follow


Pull Request Process

  1. Branch from master — use feat/, fix/, refactor/ prefixes
  2. All checks must pass — type-check + tests + lint
  3. No regressions — test count should stay the same or increase
  4. One concern per PR — don’t mix features with refactors
  5. Describe the why — PR description should explain motivation, not just list changes
  6. Update docs if needed — CLAUDE.md, OpenAPI, README

PR template


Reporting Issues

Open a GitHub issue with:
  • What you expected to happen
  • What actually happened (include error messages, logs)
  • Steps to reproduce (minimal, specific)
  • Environment — OS, Node.js version, Solana CLI version, relevant env vars
For security vulnerabilities, email security@raijinlabs.io instead of opening a public issue.

Architecture Guidelines

Before making significant changes, understand the core principles:
  1. Lucid is the control plane, not the execution authority. Agents run on decentralized providers. Lucid coordinates — it doesn’t own.
  2. Local truth, global supervision. Agent memory is agent-owned (SQLite). Deployment state is fleet-wide (Supabase). Never mix these.
  3. Interface-first, swap later. Every external dependency (IDepinStorage, INFTProvider, IDeploymentStore, ISecretsResolver) is behind a swappable interface.
  4. Events, not coupling. State changes emit events. Consumers react. Don’t create direct cross-domain function calls.
  5. L3 is operational, not canonical. Supabase stores operational projections. Chain + DePIN are the source of truth. If Supabase is lost, rebuild from L1+L2.
Read CLAUDE.md for the full architecture reference.

License

By contributing, you agree that your contributions will be licensed under: