agentleFS
PAIR-codePAIR-code/deliberate-lab/functions/AGENTS.md

deliberate-lab / functions

AGENTS.md97 starsChanged 57 days agoApache-2.0View on GitHub

Firebase Cloud Functions backend (built with esbuild): HTTP callable endpoints and Firestore document triggers. All functions are registered in src/index.ts. See also: root AGENTS.md for monorepo-wide conventions. From the repository root: Emulator tests require Java 21 for the Firebase emulator. The test runner uses firebase-test.json (in the repo root) as the emulator config. Unit-only tests (no emulator): The integration test in cohort_definitions.integration.test.ts is large and slow; it exercises full experiment lifecycle flows. Stage backend logic lives in src/stages/ and follows…

The file

Files
AGENTS.md

AGENTS.md — functions

Firebase Cloud Functions backend (built with esbuild): HTTP callable endpoints and Firestore document triggers. All functions are registered in src/index.ts.

See also: root AGENTS.md for monorepo-wide conventions.

Build & test

From the repository root:

npm run build -w functions    # Build with esbuild
npm test -w functions         # Run all tests (unit + emulator)
npm run typecheck -w functions

Emulator tests require Java 21 for the Firebase emulator. The test runner uses firebase-test.json (in the repo root) as the emulator config.

Unit-only tests (no emulator):

npm run test:unit -w functions

The integration test in cohort_definitions.integration.test.ts is large and slow; it exercises full experiment lifecycle flows.

File naming conventions

PatternPurpose
<entity>.endpoints.tsHTTP callable functions (registered in src/index.ts)
<entity>.utils.tsBusiness logic and helpers
<entity>.utils.test.tsUnit tests for business logic

Stage-specific files (src/stages/)

Stage backend logic lives in src/stages/ and follows these patterns:

PatternPurpose
<stage_type>.endpoints.tsCallable endpoints for the stage
<stage_type>.utils.tsStage-specific business logic
<stage_type>.utils.test.tsTests

New stage endpoints must be exported from src/index.ts.

Source directory overview

DirectoryPurpose
src/stages/Stage-specific backend logic
src/triggers/Firestore document triggers (see src/triggers/README.md)
src/chat/Chat-specific utilities
src/dl_api/External REST API layer (see below)
src/api/Internal API utilities (LLM provider integrations)
src/utils/Shared backend helper functions

Key files

FileRole
src/index.tsRegisters all Cloud Functions (callables + triggers)
src/app.tsInitializes StageManager — maps stage types to handlers
src/data.tsFirestore data access layer (reads/exports)
src/participant.utils.tsParticipant lifecycle — stage progression, transfers, cohort assignment

[!CAUTION] participant.utils.ts is ~1400 lines and the most complex backend file. It handles Firestore transaction chains for stage progression, cohort assignment, and participant transfers. Changes here carry a high risk of subtle race conditions. Proceed with extra care and test thoroughly.

Trigger system

Firestore document triggers live in src/triggers/. See src/triggers/README.md for the full list of triggers and the Firestore document paths they listen on.

Key trigger files:

FileListens to
participant.triggers.tsParticipant document create/update
stage.triggers.tsParticipant stage data and public stage data updates
chat.triggers.tsPublic and private chat message creation
chip.triggers.tsChip transaction creation
agent_participant.triggers.tsAgent participant lifecycle events
presence.triggers.tsRealtime Database presence changes

Agent (LLM) participants

  • agent.utils.ts — core agent orchestration logic
  • agent_participant.utils.ts — manages how LLM agents participate in experiments (stage completion, API calls, answer extraction)
  • structured_prompt.utils.ts — prompt construction for agent participants and mediators

Data access

src/data.ts is the Firestore data access layer. It provides functions like getExperimentDownload and getExperimentLogs using the Firebase Admin SDK. Do not write raw Firestore calls in endpoint files — use or extend the data access layer instead.

Endpoint conventions

  • Endpoints are defined in *.endpoints.ts files and exported from src/index.ts
  • Each endpoint returns structured responses
  • src/app.ts initializes the StageManager (from utils) which maps stage types to their handler logic
  • The src/dl_api/ directory contains the external REST API layer (key-authenticated HTTP endpoints for programmatic access)

REST API structure (src/dl_api/)

The REST API is an Express app exposed as a single Cloud Function. It uses API key authentication (not Firebase Auth) for server-to-server access.

FilePurpose
dl_api.endpoints.tsExpress app setup, middleware, route registration
experiments.dl_api.ts/v1/experiments/ route handlers
cohorts.dl_api.ts/v1/experiments/:id/cohorts/ route handlers
dl_api.utils.tsAuth middleware and request validation
dl_api_key.utils.tsAPI key creation, verification, and revocation
dl_api.test.utils.tsShared test setup utilities

How to add a new REST API endpoint

Adding a REST API endpoint touches multiple files across workspaces:

  1. Implement the route handler — add a function in the appropriate *.dl_api.ts file (or create a new one for a new resource type)
  2. Register the route — add the Express route in dl_api.endpoints.ts
  3. Update the OpenAPI spec — add the endpoint to docs/assets/api/openapi.yaml
  4. Add a Python client method — update scripts/deliberate_lab/client.py so the SDK exposes the new endpoint
  5. Write integration tests — add tests in *.dl_api.integration.test.ts

[!NOTE] REST API endpoints (/v1/...) use API key auth and are for server-to-server use. Frontend callables (used by the web app) are separate — they are Firebase onCall functions registered in src/index.ts with corresponding wrappers in frontend/src/shared/callables.ts.

How to add a new callable endpoint

Callable endpoints are Firebase onCall functions invoked by the frontend. This is the most common type of new endpoint.

  1. Implement the function — create or update a *.endpoints.ts file with the new onCall function
  2. Export from src/index.ts — add the export so Firebase registers the function
  3. Add a frontend wrapper — add a typed callable wrapper in frontend/src/shared/callables.ts (the frontend calls endpoints exclusively through these wrappers)
  4. Wire up the UI — call the new wrapper from the appropriate service or component

Firestore data model

The Firestore document hierarchy (derived from trigger paths and the data access layer):

experiments/{experimentId}
├── participants/{participantId}
│   └── stageData/{stageId}                    # participant answers
│       └── privateChats/{chatId}              # private chat messages
├── cohorts/{cohortId}
│   └── publicStageData/{stageId}              # public stage data
│       ├── chats/{chatId}                     # group chat messages
│       └── transactions/{transactionId}       # chip transactions
└── stages/{stageId}                           # stage config

Triggers listen on these paths — see src/triggers/README.md for the full list of trigger functions and the specific paths they watch.

Common pitfalls

  1. Writing raw Firestore calls in endpoint files — use or extend the data access layer in src/data.ts instead.
  2. Forgetting to export new endpoints from src/index.ts — Cloud Functions will silently ignore unregistered functions.
  3. Forgetting to add a callables.ts wrapper — the frontend calls all callable endpoints through typed wrappers in frontend/src/shared/callables.ts. A new endpoint without a wrapper is unreachable from the UI.
  4. Missing Java 21 for emulator tests — use npm run test:unit -w functions to run unit tests without the emulator.
  5. Firestore race conditions — concurrent writes to the same document (e.g., multiple participants updating public stage data simultaneously) are a recurring source of bugs. Use Firestore transactions for read-modify-write operations on shared documents.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.