unit
Contribute code
Thanks for your interest in contributing. This document covers contributions to code, infrastructure, deployment recipes, and general project documentation. Skills containing legal substance follow a different process documented in skills/CONTRIBUTING.md — that path includes attestation requirements and practicing-attorney review that don’t apply to engineering work.
In short
Section titled “In short”- Read this file in full before your first change, then read the code and tests for the behavior you’re changing — an accepted design decision isn’t always fully implemented yet, so check the implementation too.
- Run
make lint,make format-check, andmake testlocally before opening a pull request; new behavior needs tests, and user-facing changes need updated docs. - Every commit needs a DCO sign-off (
git commit -s) — pull requests with unsigned commits cannot be merged. - Changes touching authentication, authorization, audit logging, or cryptographic implementations get security review even when no path-based CODEOWNERS rule catches them automatically — say so in the PR description.
- For anything beyond a small, well-scoped item, file an issue first to discuss the approach before you invest the work.
Quick start
Section titled “Quick start”git clone https://github.com/legalquants/lq-ai.gitcd lq-aicp .env.example .env# Edit .env with at least one LLM provider API key (or use local profile)docker compose up -d # Mode 1# ORdocker compose --profile local up -d # Mode 2Running backend tests in Docker (recommended when you don’t want a local Python venv):
# api/Dockerfile.dev installs [dev] extras (pytest, respx, pytest-cov, …)# on top of the production image so the test suite runs in-container.docker build -f api/Dockerfile.dev -t lq-ai-api-dev api/docker run --rm lq-ai-api-dev python -m pytest tests/ -xThe production image (api/Dockerfile) does not install dev extras to keep
the runtime surface area minimal. Use Dockerfile.dev for any work that requires
running the test suite inside a container.
For backend development without Docker, dependencies are managed with
uv (per ADR 0023):
For ordinary reproducible setup, use uv sync --frozen --extra dev. It creates
.venv/ from the committed uv.lock without changing the lockfile. If you
intentionally change dependencies in pyproject.toml, run uv lock in that
subsystem and commit the updated lockfile — CI gates on uv lock --check.
Run each subsystem example from the repository root in its own terminal:
# Backendmake install-apicd api && .venv/bin/uvicorn app.main:app --reload --port 8000# Inference Gatewaymake install-gatewaycd gateway && .venv/bin/uvicorn app.main:app --reload --port 8001# Web (OpenWebUI fork)make install-web # installs the committed package-lock.jsoncd web && npm run devWhen deliberately changing Web dependencies, use npm install <package> (or
npm uninstall <package>) and commit both web/package.json and
web/package-lock.json. Use npm ci for ordinary setup and verification.
Run the test suite before submitting:
# From the repository rootmake lint # Python ruff/mypy + Web scoped Svelte checkmake format-check # Python formatting checkmake test # Python local-loop suites + Web Vitest
# Web checks can also be run independentlymake web-check # npm run check:lq-aimake web-test # npm run test:frontend -- --runWhat to work on
Section titled “What to work on”Working with an AI coding agent (Claude Code, Cursor, …)? Start it on the cold-start guide for coding agents — read-order, the build loop, dev-environment hard rules, and how to take a roadmap item to a merged PR.
The project’s Deferred Enhancements list (PRD §9) catalogs ~50+ bounded enhancements where the architectural slot exists and the implementation is well-defined. Items tagged P1 are particularly welcome for v1.5+. A few that are well-shaped for first-time contributors:
- DE-013 Saved Prompts Library (S effort) — per-user saved prompts in a sidebar; CRUD plus promote-to-skill.
- DE-015 Voice / Dictation Input (S) — Web Speech API toggle on the chat input.
- DE-031 Reverse proxy / TLS recipes (S) — document Caddy / Traefik / nginx integration patterns.
- DE-103 IP allowlisting and geo-restriction (S) — configurable IP allowlist for the web app and Word add-in.
- DE-105 Outbound proxy support (S) —
HTTPS_PROXY/NO_PROXYconfiguration in the Inference Gateway.
For larger items (M and L effort), please file an issue first to discuss approach before opening a PR. We do not want anyone to invest weeks of work that turns out to conflict with an architectural choice or another in-flight contribution.
For features not on the deferred-enhancements list, please file an issue describing the use case and the proposed approach. Pull requests for unfiled features are welcome but at higher risk of bouncing if they conflict with the project’s direction.
Pull request process
Section titled “Pull request process”- Fork the repository and create a branch from
main. Branch names should describe the work:feat/saved-prompts,fix/citation-engine-empty-result,docs/clarify-tier-config. - Make your changes following the code style and testing requirements below.
- Add or update tests covering the change. PR CI enforces coverage as a
ratchet (
.github/workflows/ci.yml):--cov-fail-under=80forapi/and--cov-fail-under=88forgateway/, each pinned at or below the measured figure so a PR that lowers coverage fails. - Update documentation — the PRD, README, skill-authoring guide, or capability docs as relevant. If your change affects user-facing behavior, the docs need to reflect it.
- Sign your commits per the DCO requirement (see Sign-off below). PRs without DCO sign-off cannot be merged.
- Open the PR with a description that explains what changed, why, and how to verify. Link to any relevant issue or DE-### entry in the PRD.
- Respond to review — see Review timelines for what to expect and how the queue is prioritized. Substantive review feedback usually requires changes; small style nits can be deferred to follow-ups.
- Current PR CI must pass — API runs
uv lock --check,ruff check, andruff format --checkforapi/andscripts/,mypy app, andpytest -n auto -qwith pgvector Postgres (each xdist worker gets its own session-scoped disposable database via the conftest fixture, so workers are fully isolated); Gateway runsuv lock --check, ruff check/format,mypy app, andpytest -q; Web runsnpm run check:lq-aiandnpm run test:frontend -- --run; the Release image job runsscripts/release-image-check.sh(the skills-corpus guard inapi/Dockerfile.release). The path-triggered Stack smoke workflow also runs on PRs that change the specified API/Gateway/Web dependency manifests and locks, Dockerfiles, compose, API migrations, its script, or its workflow. PRs with failing CI are not merged. - At least one maintainer approval is required to merge. For changes affecting multiple subsystems, two approvals are preferred.
Squash-and-merge is the default; merge commits are reserved for cases where the per-commit history meaningfully aids future debugging.
Sign-off (Developer Certificate of Origin)
Section titled “Sign-off (Developer Certificate of Origin)”LQ.AI uses the Developer Certificate of Origin (DCO) — not a CLA. The DCO is a lightweight assertion that you have the right to contribute the work under the project’s Apache 2.0 license. Industry standard, sufficient legal cover, no separate paperwork.
Every commit must be signed off:
git commit -s -m "Your commit message"This adds a trailer to your commit message:
Signed-off-by: Your Name <your.email@example.com>The git config user.email you sign off as must match the email associated with
your GitHub account or be in your verified emails list. Project policy requires
DCO sign-off on every commit; PRs with unsigned commits cannot be merged.
If you forget to sign off, amend your commits before pushing:
git commit --amend -s --no-edit # most recent commitgit rebase --signoff main # all commits since main divergedCode style
Section titled “Code style”Python (api/, gateway/, scripts)
Section titled “Python (api/, gateway/, scripts)”- Formatter:
ruff format(Black-compatible). CI rejects unformatted code. - Linter:
ruff checkwith the project’sruff.tomlconfig. Most pyflakes / pycodestyle / pyupgrade / bugbear rules enforced. - Type checker:
mypyin strict mode for the gateway; standard mode for the backend (strict-mode migration is a tracked enhancement, DE-### TBD). - Type annotations: required on all new public functions and class methods. Internal helpers can omit return types where obvious; public API contracts require full annotations.
- Imports: sorted by
ruff(isort-compatible). Standard library first, then third-party, then local. - Docstrings: required on public modules, classes, and functions in the gateway and backend. Format: triple-quoted, summary line, blank line, detail. Descriptive variable names reduce the need for inline comments.
- Async: prefer
async deffor I/O-bound functions; usehttpx.AsyncClientrather thanrequests. Sync helpers are fine for CPU-bound or test code. - Exceptions: raise typed errors from each subsystem’s
app.errorsmodule (api/app/errors.py, gateway/app/errors.py) —LQAIErrorand its subclasses. Do not raise bareException. Per ADR 0003, the two subsystems each ship parallel hierarchies; the cross-subsystem contract is the error-code enum in the OpenAPI sketches plus the conformance test intests/test_error_code_contract.py.
JavaScript / TypeScript (web/)
Section titled “JavaScript / TypeScript (web/)”- Formatter: Prettier with the project’s
.prettierrc. Run it deliberately on files you change; the current PR workflow does not run a Web formatting gate. - Static check:
npm run check:lq-airuns the scoped Svelte/TypeScript check used by current PR CI. The inherited full-forknpm run lintscript mutates files and is not the PR static-check contract. - TypeScript: required for new files; gradual migration of legacy
.jsfiles welcome but not required for unrelated changes. - Framework: SvelteKit. The
web/codebase is a fork of OpenWebUI, which is a SvelteKit app — extensions and customizations stay in Svelte. Do not introduce React intoweb/. The Word add-in (word-addin/, M3) uses Office.js with React; theweb/codebase does not. - Component conventions: match the OpenWebUI conventions for shared components (
web/src/lib/components/**, untouched per ADR 0009). Withinweb/src/lib/lq-ai/**, prefer thelqprimitives (web/src/lib/lq-ai/components/shared/) and their typed token vocabulary for new or changed components. See ADR 0043 for the contract and bounded reference implementation; migration of the remaining shell is separate work.
Configuration files
Section titled “Configuration files”- YAML: 2-space indent. Use anchors and aliases sparingly; prefer explicit duplication over clever YAML.
- TOML: for Python project configuration (
pyproject.toml,ruff.toml). - Markdown: GitHub-flavored. Headings use
#, not===. Wrap at ~100 chars in prose; do not wrap inside code blocks.
Commit messages
Section titled “Commit messages”- Imperative mood. “Add tier-config endpoints” not “Added tier-config endpoints”.
- Subject under ~70 chars; body wrapped at ~72 chars.
- Reference issues in the body:
Closes #123,Refs DE-103. - No marketing language in commit messages. Describe what changed and why; the changelog is for marketing.
Testing requirements
Section titled “Testing requirements”The project takes testing seriously because the substantive correctness of the legal-AI work product depends on it.
Coverage target
Section titled “Coverage target”Pytest coverage target is 80% for api/ and 90% for gateway/ (docs/PRD.md, coverage gates). PR CI enforces it
as a ratchet (.github/workflows/ci.yml): --cov-fail-under=80 for api/ and
--cov-fail-under=88 for gateway/, each pinned at or below the measured
figure so a PR that lowers coverage fails. New code should be covered by
tests; bug fixes should include a regression test that fails before the fix
and passes after.
Test categories
Section titled “Test categories”- Unit tests — fast, no external dependencies. Mock the Inference Gateway, the database, and any provider APIs.
- Integration tests — API PR tests run with a real pgvector Postgres service. These exercise flows that need database behavior rather than mocks alone.
- Provider-integration tests — marked
providerand require provider API keys. They are not a separate current PR CI job; run them locally when a change specifically affects provider integration and credentials are available. - End-to-end tests — the deterministic Cypress track runs nightly and on
manual dispatch (
.github/workflows/e2e.yml), not on every PR; the live-model track stays gated behindCYPRESS_LLM=1, which CI never sets. - Fuzzing — continuous fuzzing is not part of the current PR workflow.
Release image skills-corpus check
Section titled “Release image skills-corpus check”api/Dockerfile.release bakes the repo-root skills/ corpus into the published api image, and half of that corpus is the skills/community submodule. The Dockerfile fails the build unless at least one skills/community/skills/*/SKILL.md manifest is present, so a checkout without submodules cannot publish an image that is silently missing those skills. CI runs the check on every PR (release-image-checks in .github/workflows/ci.yml). It builds only the skills stage of the Dockerfile, so it needs no dependency install and finishes in seconds.
Run it locally after touching api/Dockerfile.release, .gitmodules, or the release checkout in .github/workflows/release.yml (needs docker and a recursive checkout):
git submodule update --init --recursive./scripts/release-image-check.shIt asserts that this checkout bakes the community manifests, and that an empty submodule directory, a submodule root carrying only README and LICENSE, and a skills/ tree with no manifest each stop the build at the guard. Set FULL_IMAGE=1 to also build the complete api release image (slow; pulls docling and torch).
Stack smoke test (build + boot the whole stack)
Section titled “Stack smoke test (build + boot the whole stack)”The suites above run in-process and never boot the real servers, so they miss whole classes of breakage: a server that won’t start (uvicorn), a Redis client that fails on connect (the arq workers), a lazily-imported dependency that breaks (docling is only imported inside ingest jobs), or an OpenWebUI-core build failure (the web production build is outside the scoped typecheck and the Vitest suite). The stack smoke test closes that gap by building every default-profile image, booting the full compose stack, waiting for every healthcheck, probing the api/gateway/web health endpoints and the ingest worker’s lazy imports, then holding for a soak period and failing if any container restarted.
CI runs it (.github/workflows/stack-smoke.yml) on PRs that touch dependency manifests — pyproject.toml, web/package.json/package-lock.json, Dockerfiles, docker-compose.yml — which covers dependabot PRs, plus pushes to main and manual dispatch.
Run it locally before submitting a change that could break the stack at build or boot time (a dependency bump, a Dockerfile or compose edit, a new migration):
./scripts/stack-smoke.shNotes for local runs:
- No provider API keys are needed — nothing in the smoke performs inference. If you have no
.env, the script writes one with dummy secrets; an existing.envis respected. - It operates on the same compose project as your dev stack and recreates the containers (
--force-recreate) so the restart-count assertion starts from zero. Named volumes (Postgres data, object-store files, model caches) are untouched. As always, neverdocker compose down -v. - A cold build needs roughly 25 GB of free disk and 20–30 minutes (the api image pulls docling/torch); warm rebuilds are much faster.
- Tune with
SOAK_SECONDS(default 75) andWAIT_TIMEOUT(default 900) environment variables. - On failure the script reports which phase failed (build / boot / probes / soak), each container’s state (exit code, OOM kill, restart count), the last healthcheck probe outputs, disk space, and the last 60 log lines per service; full compose logs land in
stack-smoke-logs/(gitignored). CI additionally uploads that directory as a workflow artifact and writes the state dump to the job summary. - It proves “builds, migrates, boots, and holds” — it does not prove features work. Feature-level verification still belongs to the test categories above.
Test stack conventions (Python)
Section titled “Test stack conventions (Python)”Locked-in choices so new tests don’t drift across api/ and gateway/. Changes to these defaults need a PR with rationale.
- Test runner:
pytest. No alternative. - Async tests:
pytest-asynciowithasyncio_mode = "auto"configured inpyproject.toml. Async test functions are written asasync def test_*(...)without a per-test decorator. We pickedpytest-asynciooveranyio’s test plugin because the project’s runtime is asyncio-only — we never need trio compatibility, andpytest-asynciohas the larger ecosystem. - HTTP client in tests:
httpx.AsyncClientwithASGITransportfor in-process FastAPI tests; noTestClient. Real-network calls in tests are forbidden outside theprovider-marked tests. - Test database: session-scoped fixture runs Alembic migrations once against a per-CI-run Postgres database; per-test fixture wraps each test in a transaction that rolls back on teardown. No truncation between tests; no test-specific migrations. Both subsystems share
tests/conftest.pypatterns. - API test environment (
api/tests/conftest.py): arq’s pool creation fails at once, since no Redis runs in tests; a test that needs a working queue patches the pool or the enqueue helper. bcrypt hashes at its minimum cost (BCRYPT_ROUNDS=4) unless the environment sets one. A test whose code commits through its own engine and reads global state takesisolated_db_url, a fresh copy of the migrated database, instead of the shared one. - Test data: factory pattern using
polyfactoryfor Pydantic models; no hand-written fixture dictionaries except for canonical examples that stay readable inline. - Provider mocking:
respxfor httpx-level mocks; record-replay fixtures for end-to-end provider flows undertests/fixtures/providers/. - Time and randomness:
freezegunfor time,random.seed(0)at the top of any test that uses randomness. Flaky tests are not tolerated; if you find one, fix it or skip it with a tracked issue.
Test markers
Section titled “Test markers”Standard markers are declared in each subsystem’s pyproject.toml where
applicable, so pytest --strict-markers rejects typos:
integration
provider
slow
make test; current PR pytest has no marker filtere2e
docs/test-strategy.md)pytest -m "not provider and not slow" is the local-loop default; make test runs this.
JavaScript/TypeScript tests (web/)
Section titled “JavaScript/TypeScript tests (web/)”The OpenWebUI fork is SvelteKit. New unit and component tests use Vitest (Svelte’s standard). Don’t introduce Jest unless there’s a concrete reason — Vitest is closer to SvelteKit’s tooling and has fewer ESM-vs-CJS pitfalls.
- Component tests:
@testing-library/sveltewith Vitest. - Type checking in tests: test files are
.ts/.svelteand passnpm run check:lq-ai. - Snapshot testing: discouraged for component output; preferred for stable structured data (e.g., backend-returned shapes).
When to write what kind of test
Section titled “When to write what kind of test”Change type Required tests
- Bug fix
- Regression test (unit if possible; integration if the bug is multi-component)
- New API endpoint
- Unit tests for the handler logic + integration test exercising the endpoint end-to-end + OpenAPI schema-conformance test
- New provider adapter
- Provider-integration tests (gated behind
-m provider); unit tests with mocked provider responses for the request/response shape - New skill (engineering side; the skill content itself goes through the skills/CONTRIBUTING.md path)
- A worked-example test verifying the skill renders and produces structured output of the expected shape
- New deployment recipe
- Documented steps + a CI verification job that runs the recipe in a clean environment
- Documentation only
- No new tests; no current Markdown CI gate
Security
Section titled “Security”If you discover a security vulnerability, please do not file a public GitHub issue. Follow the disclosure process in SECURITY.md:
- Email security@legalquants.com (or the address documented in
SECURITY.mdat the time you read this) with a description of the vulnerability and reproduction steps. GPG key available at the URL inSECURITY.md. - We will acknowledge receipt within 72 hours.
- We will fix critical issues within 30 days and coordinate disclosure timing with you.
- After fix and disclosure, the advisory is published on GitHub Security Advisories with credit to the reporter (unless you prefer to remain anonymous).
The project includes safe-harbor language committing not to pursue legal action against good-faith security researchers who follow the coordinated-disclosure process.
For security-affecting changes (not vulnerabilities — changes you want to propose to the project that have security implications), file a normal PR but flag the security implications in the description and tag a maintainer for direct review. Examples: changes to authentication flows, audit logging, the Inference Gateway’s tier-derivation logic, the Anonymization Layer, encryption configuration, supply-chain artifacts.
.github/CODEOWNERS auto-routes four paths to the project’s security reviewers in addition to the maintainer team, and a PR touching any of them is held until security review approves it: gateway/** (the Inference Gateway, the project’s only component holding privileged provider API keys), docs/security/**, .github/workflows/**, and SECURITY.md. Routing is by path only — if your change touches authentication, authorization, audit logging, or cryptographic implementations somewhere else in the tree, say so in the PR description and request security review yourself; nothing routes those automatically.
Documentation expectations
Section titled “Documentation expectations”If your change affects user-facing behavior, the documentation must be updated in the same PR. The relevant docs:
docs/PRD.md— the canonical specification. Capability changes go here. PRD edits should follow the existing structure (see PRD’s own changelog convention).README.md— the front-door doc. Update if your change affects how users get started, what the project does, or the high-level capability list.docs/skill-authoring-guide.md— if your change affects how skills work or what’s expected of skill authors.docs/playbook-authoring-guide.md— if your change affects Playbooks.docs/deployment-cookbook.md— if your change affects deployment.docs/compliance/— if your change affects compliance posture (e.g., new audit-log field, new tier-handling logic, new data-flow path that affects a control mapping).docs/security/— if your change affects security posture (e.g., new dependency that affects the SBOM story, new endpoint that affects the threat model).- API changes — the OpenAPI schema is generated from the FastAPI handlers; update handlers, run
make openapito regenerate the schema, and commit the regenerated schema.
PRs that change behavior without updating docs will be asked to add the doc changes before merge.
Porting skills from external sources
Section titled “Porting skills from external sources”Skills may be ported from external corpora (law firm knowledge bases, open-source legal-AI repositories, academic datasets, etc.) if the licence and provenance allow. Porting is a special case of the skill-contribution workflow documented in skills/CONTRIBUTING.md; the additional requirements below apply in addition to the standard skill-authoring steps.
Attestation
Section titled “Attestation”Every ported skill PR description must include an attestation paragraph signed by a practicing attorney (the PR author, a co-author, or a named legal reviewer). Template:
I, [Name], a licensed attorney in [jurisdiction(s)], attest that:
- I have reviewed the ported skill against the original source material and confirm the substance is accurately represented.
- The upstream licence ([SPDX identifier]) permits this use under the terms stated in NOTICES.md.
- Any jurisdictional limitations of the source material are reflected in the skill’s
jurisdiction:frontmatter field.- This skill does not constitute legal advice and is labelled accordingly in the skill frontmatter.
Pull requests without a complete attestation paragraph will not be merged. Agents do not attest — the human contributor is the attesting party.
Provenance preservation
Section titled “Provenance preservation”The upstream source must be recorded in three places:
-
Skill frontmatter — add a
source:key under thelq_ai:extension block:lq_ai:source:uri: "https://example.com/original-skill-repo"license: "Apache-2.0"retrieved_at: "2026-05-14" -
NOTICES.md — add a row to the per-skill provenance table at the repo root. See
NOTICES.mdfor the column format. -
Commit message — include the upstream URI in the commit body:
Ported from https://example.com/original-skill-repo (Apache-2.0).
Attribution requirements
Section titled “Attribution requirements”If the upstream source requires attribution (e.g., a CC-BY licence), the attribution text must appear in:
- The skill’s
SKILL.mdunder an “Attribution” heading. - The NOTICES.md row for that skill.
Questions about licence compatibility should be directed to the maintainer team before opening the PR. When in doubt, do not port — create a new skill inspired by the source instead.
Reviewer expectations
Section titled “Reviewer expectations”Reviewers will look for:
- Correctness — does the change do what it claims to do?
- Tests — does the change have adequate test coverage?
- Style — does the change follow the project’s conventions?
- Clarity — is the change readable and maintainable?
- Compatibility — does the change preserve backward compatibility, or if not, is the breaking change documented and justified?
- Security implications — does the change introduce new attack surface, weaken existing protections, or change the data-flow path? If so, has it been thought through?
- Performance implications — does the change add latency or memory overhead in the request path? If so, is the trade-off documented?
- Documentation — has the relevant doc been updated?
Reviewers are also expected to be:
- Constructive — feedback is about the work, not the contributor. Suggest specific changes rather than abstract complaints.
- Timely — work the queue in the published order and communicate when you cannot meet the current target. See Review timelines; the target is stated alongside the measured median rather than on its own.
- Decisive — approve, request changes, or comment with a specific question. Do not leave PRs in limbo.
If a PR has been waiting longer than the current target, ping a maintainer on the PR itself, or raise it in GitHub Discussions.
Review timelines
Section titled “Review timelines”Review capacity is this project’s binding constraint, and this section states it honestly rather than publishing a target the project does not meet. Adopted by ADR 0034.
The target. First substantive maintainer response within 7 days of a PR being opened, faster for security fixes and small bug fixes with regression tests.
The measurement. The median time to first response is measured over all PRs opened in the period, excluding automated dependency bumps, and published at the committee’s checkpoints alongside the target. When the measured median exceeds the target, the number is published anyway — that is the point of measuring it. Sustaining a median under 7 days for a quarter is one of the three preconditions for setting a 1.0 date (ADR 0030).
The figure comes from scripts/pr_response_time.py, which needs only Python 3.12+ and a
read-only GitHub token (GITHUB_TOKEN, or whatever gh auth token returns):
python scripts/pr_response_time.py --quarter 2026-Q3 # one quarterpython scripts/pr_response_time.py --month 2026-09 # one monthpython scripts/pr_response_time.py --since 2026-07-01 --until 2026-09-30 # any rangepython scripts/pr_response_time.py --quarter 2026-Q3 --json # machine-readableIt prints the median over answered PRs, the count of PRs opened, how many were excluded as
automated dependency bumps, every PR still waiting with how long it has waited, and the exact
rule it applied for “substantive maintainer response” together with what that rule gets wrong.
Reading the maintainer team needs the read:org scope; without it, pass --maintainer LOGIN.
The cadence is the maintainers’ call: a quarterly run matches the ADR 0030 checkpoint, and a
monthly run surfaces a bad stretch while it can still be corrected. Automating the publication
is DE-406.
Review slots. Maintainers work the open queue in a recurring weekly block, in this priority order:
- Ratification documents (ADRs and governance amendments awaiting the committee).
- PRs on the 1.0 gate, labelled
road-to-1.0. - Follow-ups for contributors who have volunteered for a lane, and attorney acceptance runs.
- Everything else, oldest first.
If your PR sits outside these and has waited, say so on the thread — an unreviewed PR that nobody has flagged is easy to lose.
Helping with the constraint. Review help is the most valuable contribution to this project right now. GOVERNANCE.md describes the trusted reviewer rung — review authority without merge authority — and GOVERNANCE.md publishes the criteria for promotion to maintainer. Both are open; nominations go through any maintainer.
Code of Conduct
Section titled “Code of Conduct”This project follows the Contributor Covenant. The full text is in CODE_OF_CONDUCT.md. Briefly: be kind, assume good faith, focus on the work, and engage with disagreements substantively rather than personally.
Reports of unacceptable behavior go to conduct@legalquants.com. Reports are confidential and will be reviewed by maintainers; meaningful violations result in escalating consequences from a private warning through to a permanent ban.
License
Section titled “License”By contributing to LQ.AI, you agree that your contributions will be licensed under the project’s Apache License 2.0. The DCO sign-off (above) is your assertion that you have the right to contribute the work under that license.
Questions?
Section titled “Questions?”- General questions → GitHub Discussions.
- Bug reports → GitHub Issues with the
buglabel and a reproduction case. - Feature requests → GitHub Issues with the
enhancementlabel; reference the PRD §9 Deferred Enhancements entry if one exists. - Security → security@legalquants.com (see
SECURITY.md). - Skill contributions → see
skills/CONTRIBUTING.md— the skill-specific contribution path.
Thanks for contributing.