Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/arrozet/caret/llms.txt

Use this file to discover all available pages before exploring further.

Caret is an evolving codebase shared across a team of contributors and AI agents. Consistent naming, clear architecture boundaries, disciplined commit messages, and thorough documentation make the project easier to navigate, review, and extend. This page collects the conventions that apply across all layers of the stack — read it before opening your first pull request.
When working on a specific subsystem, load the relevant .agents/skills/ file first. Each skill file describes the current implementation state, preferred patterns, and known gotchas for that area — reading it will save you from rediscovering assumptions that are already documented.
SubsystemSkill file
Frontend (React, Tiptap, Y.js UI).agents/skills/caret-frontend/SKILL.md
Backend services (Node, FastAPI).agents/skills/caret-backend/SKILL.md
Infrastructure and deployment.agents/skills/caret-deployment/SKILL.md
Testing strategy.agents/skills/caret-testing/SKILL.md

Code Style by Layer

Naming conventions follow each ecosystem’s established best practices. The rules differ between the frontend, Node backend services, and the Python AI service — use the correct convention for the layer you are working in.

Frontend (React / TypeScript)

ElementConventionExample
React componentsPascalCaseEditorPage.tsx, CollaborationPresenceBar.tsx
Functions, variables, propertiescamelCaseuserData, isVisible, documentTitle
React hookscamelCase starting with useuseAuth, useCollaborationSession, useSaveDocument
Event handlerscamelCase prefixed with handlehandleClick, handleSubmit, handleUserInput
ConstantsUPPER_SNAKE_CASEMAX_FILE_SIZE, API_BASE_URL
Store and hook filenamescamelCaseauthStore.ts, useTheme.ts
When in doubt, follow the existing patterns in the feature you are working in. Current stores and hooks use camelCase filenames — don’t introduce snake_case filenames in the frontend just because an older doc mentions them.

Backend — Node Services (TypeScript)

ElementConventionExample
Variables, functions, methodscamelCasegetUserById, documentRepository, userAction
Classes and constructorsPascalCaseDocumentService, CollaborationController, UserManager
File namessnake_caseuser_repository.ts, document_routes.ts
Where a file already exposes both camelCase and snake_case exports for backwards compatibility, preserve the existing aliases rather than renaming them.

Backend — Python AI Service (FastAPI)

ElementConventionExample
Variables, functions, methodssnake_caseuser_id, create_user, get_all_items
Classes, Pydantic models, SQLAlchemy modelsPascalCaseUserCreate, ItemResponse, AIAgentService
File names / module namessnake_caseai_router.py, document_repository.py, config.py

SOLID Principles

Caret applies SOLID principles consistently across all layers. Understanding what each principle means in practice will help you structure new code and review existing contributions.

Single Responsibility Principle

Every module, class, and function should have one reason to change. A route handler should only parse the HTTP boundary and call a service — it should not contain business logic or SQL queries. A repository should only contain database access — it should not call external HTTP APIs.

Open/Closed Principle

Code should be open for extension but closed for modification. Prefer adding new service implementations, new Tiptap extensions, or new AI router endpoints over modifying existing ones. Design abstractions (interfaces, base classes, extension hooks) so that new behaviour can be added without touching proven code.

Liskov Substitution Principle

Subtypes must be substitutable for their base types without breaking the program. If a service accepts a repository interface, any concrete repository implementation must honour the full contract — not just the methods it needs. Avoid implementations that silently skip interface methods or throw unexpected errors for valid inputs.

Interface Segregation Principle

Prefer small, focused interfaces over large general-purpose ones. A document read service should not depend on a write interface just because both live in the same repository class. Split interfaces by the consumer’s needs, not by the provider’s convenience.

Dependency Inversion Principle

High-level modules should not depend on low-level modules — both should depend on abstractions. Route handlers should receive their service dependencies through constructor injection rather than importing concrete implementations directly. The document-service and collab-service already use manual constructor wiring — follow that pattern.

Architecture Layer Rule

Every service in Caret follows a strict four-layer hierarchy. Violations — such as importing Drizzle ORM or SQLAlchemy directly into a route handler — will be rejected in code review.
route / controller / handler

    service

   repository

  database / model / schema
LayerResponsibilityMust not
Route / controller / handlerParse HTTP or WebSocket input, validate, call services, return HTTP responsesContain business logic or SQL
ServiceBusiness rules, orchestration, data mappingImport ORM models or make raw SQL queries
RepositoryAll SQL and ORM accessContain business rules or HTTP concepts
DTO / schema / modelTyped data shapes onlyContain logic

Conventional Commits

All commit messages must follow the Conventional Commits standard. This makes the git history scannable, simplifies changelog generation, and helps reviewers understand the scope of a change at a glance.

Format

type(scope): short imperative description

Commit Types

TypeWhen to use
featA new feature or capability visible to users or other services
fixA bug fix
docsDocumentation changes only
styleFormatting, whitespace, missing semicolons — no logic changes
refactorCode restructuring that neither adds a feature nor fixes a bug
testAdding or fixing tests
choreBuild tooling, dependency updates, CI configuration

Examples

feat(editor): add bold formatting shortcut
fix(auth): resolve session expiry on page refresh
docs(api): add endpoint description for document creation
refactor(collab-service): extract persistence logic into CollabPersistenceService
test(document-service): add integration tests for folder CRUD routes
chore(deps): upgrade Vitest to v4
Keep the subject line under 72 characters. Use the body for context on why the change was made when it is not obvious from the subject line.

Git Workflow

1

Branch from main

Create a dedicated branch for each significant change. Use a descriptive name that reflects the type and scope:
git checkout main
git pull
git checkout -b feat/editor-bold-formatting
2

Make small, focused commits

Commit related changes together and unrelated changes separately. Small commits are easier to review, bisect, and revert if needed. Avoid combining a refactor with a new feature in the same commit.
3

Open a pull request

Push your branch and open a PR against main. Describe what the change does and why, link any relevant issues, and confirm that lint, type checks, and tests all pass locally before requesting review.
git push origin feat/editor-bold-formatting
4

Address review feedback

Respond to comments with additional commits on the same branch. Once approved and all checks pass, merge into main. Production deployments are triggered from the prod branch.

Documentation Standards

All new functions, classes, and non-trivial modules must include documentation written in English.
  • Docstrings — every function and class needs a docstring that describes its purpose, parameters, and return value. This applies to both TypeScript (JSDoc) and Python (PEP 257 docstrings).
  • Inline comments — add comments for technically complex logic, non-obvious implementation choices, algorithm explanations, and design decisions. Avoid restating what the code already clearly says.
  • Language — all documentation, comments, and commit messages must be written in English, regardless of the contributor’s primary language.
// TypeScript — JSDoc example
/**
 * Retrieves a document by its ID and verifies the requesting user has read access.
 * Throws a 403 ForbiddenError if the user is not a member of the document's workspace.
 */
async function getDocumentById(docId: string, userId: string): Promise<Document> { ... }
# Python — PEP 257 example
async def search_workspace_context(workspace_id: str, query: str, limit: int = 5) -> list[EmbeddingResult]:
    """
    Search the vector store for document chunks semantically similar to the query.

    Args:
        workspace_id: The workspace to scope the search to.
        query: The natural-language query string to embed and search.
        limit: Maximum number of results to return. Defaults to 5.

    Returns:
        A list of EmbeddingResult objects ordered by similarity score descending.
    """

Build docs developers (and LLMs) love