Developer Guide
Developer Guide
Section titled “Developer Guide”This guide describes how to build the LMA project from source code, run local development, and contribute.
Table of Contents
Section titled “Table of Contents”- Prerequisites
- Repository Structure
- Building and Publishing
- Local UI Development
- WebSocket Server
- Virtual Participant
- WebSocket Test Client
- Linting
- Continuous Integration
- Customization Entry Points
- Contributing
Prerequisites
Section titled “Prerequisites”You need the following installed on your machine:
| Dependency | Version |
|---|---|
| bash | Linux, macOS, or Windows WSL |
| Node.js | >= 22.22.2 (the exact pin is in .nvmrc; make setup-node installs it via nvm) |
| npm | Bundled with Node.js |
| Docker | Running (required for SAM builds). On macOS, use Docker Desktop. |
| zip | Any version |
| Python 3 | With pip3 |
| virtualenv | pip3 install virtualenv |
| AWS CLI | Configured with credentials |
| AWS SAM CLI | >= 1.118.0 |
Repository Structure
Section titled “Repository Structure”lma-main.yaml # Main CloudFormation orchestration templatepublish.sh # Build and publish scriptVERSION # Current version (0.3.0)lma-ai-stack/ # Core: Lambdas, AppSync, DynamoDB, UI ├── deployment/ # CloudFormation templates ├── source/ │ ├── lambda_functions/ # 19 Python Lambda functions │ ├── lambda_layers/ # Shared Python/Node layers │ ├── appsync/ # GraphQL schema and 39 resolvers │ └── ui/ # React web application ├── Makefile # Build orchestration └── config.mk # Build configurationlma-websocket-transcriber-stack/ # WebSocket server (TypeScript/Fastify on Fargate)lma-virtual-participant-stack/ # VP (TypeScript/Playwright + CloakBrowser on ECS)lma-vpc-stack/ # VPC networkinglma-cognito-stack/ # Cognito authlma-meetingassist-setup-stack/ # Strands agent configlma-bedrockkb-stack/ # Bedrock Knowledge Baselma-llm-template-setup-stack/ # LLM prompt templateslma-chat-button-config-stack/ # Chat button configlma-nova-sonic-config-stack/ # Nova Sonic configdocs/ # Documentation (you are here)Building and Publishing
Section titled “Building and Publishing”Using LMA CLI (Recommended)
Section titled “Using LMA CLI (Recommended)”Set up your development environment (installs Node.js, Python venv, SDK, and CLI):
make setupCheck Prerequisites
Section titled “Check Prerequisites”lma-cli check-prereqsBuild and Deploy in One Step
Section titled “Build and Deploy in One Step”The simplest way to build from source and deploy:
lma-cli deploy --stack-name LMA --from-code . --admin-email user@example.com --waitThis builds all stacks, publishes artifacts to S3, and deploys the CloudFormation stack in one command. Use --wait to monitor progress with real-time event streaming.
Publish Only (without deploying)
Section titled “Publish Only (without deploying)”lma-cli publish --source-dir . --region us-east-1This packages all sub-stacks, uploads to S3, and outputs a CloudFormation template URL you can use later.
Deploy from Published Template
Section titled “Deploy from Published Template”lma-cli deploy --stack-name LMA --template-url <template-url> --admin-email user@example.com --waitSee the LMA CLI Reference for the full list of options.
Both lma-cli publish and lma-cli deploy --from-code use content-hash-based checksums to skip rebuilding unchanged stacks on subsequent runs.
macOS Notes
Section titled “macOS Notes”Publishing and deploying from source works on both Linux and macOS (including Apple Silicon). On macOS:
- Docker Desktop must be installed and running. Docker Desktop handles x86_64 emulation via Rosetta — no additional QEMU setup is needed.
- Enable Rosetta emulation: Open Docker Desktop → Settings → General → Enable “Use Rosetta for x86_64/amd64 emulation on Apple Silicon”, then restart Docker Desktop.
- SAM CLI container preference: If SAM CLI is configured to use Finch (via
/Library/Preferences/com.amazon.samcli.plist), but Finch is not installed, builds will fail. Fix with:Or remove the preference entirely to let SAM CLI auto-detect Docker:Terminal window sudo plutil -replace DefaultContainerRuntime -string docker /Library/Preferences/com.amazon.samcli.plistsudo rm /Library/Preferences/com.amazon.samcli.plist
Local UI Development
Section titled “Local UI Development”The React UI is in lma-ai-stack/source/ui/. The simplest way to start the UI dev server is:
make ui-start STACK_NAME=<your-stack-name>This automatically retrieves the .env configuration from your deployed stack’s CloudFormation outputs, installs dependencies, and starts the development server at http://localhost:3000. The page reloads on edits.
Other npm scripts (run from lma-ai-stack/source/ui/):
npm test— Run Jest tests in watch modenpm run build— Production build tobuild/
WebSocket Server
Section titled “WebSocket Server”The WebSocket transcription server is in lma-websocket-transcriber-stack/source/app/.
cd lma-websocket-transcriber-stack/source/appnpm installnpm run build # TypeScript compilationnpm test # Jest testsThe server is a TypeScript/Fastify application deployed as a Docker container on ECS Fargate behind an Application Load Balancer.
Virtual Participant
Section titled “Virtual Participant”The VP backend is in lma-virtual-participant-stack/backend/.
cd lma-virtual-participant-stack/backendnpm installnpm run build # TypeScript compilationLocal Docker Testing
Section titled “Local Docker Testing”The simplest way to run the VP locally against a deployed LMA stack is via the Makefile:
make vp-start STACK_NAME=<your-stack-name> PLATFORM=WEBEX MEETING_ID=<meeting-id>This wraps lma-virtual-participant-stack/backend/local-test.sh: it fetches configuration from CloudFormation, writes .env.local, builds the Docker image, and runs the container with VNC on ports 5900 (VNC client) and 5901 (noVNC web browser).
Other useful targets:
| Target | Purpose |
|---|---|
make vp-start-dev ... | Dev mode: source-mounted, auto-reloads on TS changes |
make vp-start-reuse ... | Reuse existing .env.local (preserves manually-added secrets like ELEVENLABS_API_KEY) |
make vp-stop | Stop and remove the lma-vp-local-test container |
make vp-logs | Tail container logs (dev mode) |
make vp-shell | Open a shell inside the running container |
Because the VP runs on Linux in ECS, the most production-like local environment is a Linux EC2 instance edited via VSCode Remote-SSH with VNC previewed on your laptop. For the full workflow (EC2 setup, secret handling, dev-mode auto-reload, and the VSCode stale-port-forwarding gotcha), see Virtual Participant Local Development.
Manual Step Function Testing
Section titled “Manual Step Function Testing”Execute the VP scheduler Step Function directly:
aws stepfunctions start-execution \ --state-machine-arn arn:aws:states:us-east-1:123456789012:stateMachine:SchedulerStateMachine-XXXX \ --input '{"apiInfo":{"httpMethod":"POST"},"data":{"meetingPlatform":"Zoom","meetingID":"12345678","meetingPassword":"a1b2c3","meetingName":"Test","meetingTime":"","userName":"Bob"}}' # pragma: allowlist secretSupported httpMethod values: POST (join/schedule), GET (list scheduled), DELETE (cancel scheduled).
WebSocket Test Client
Section titled “WebSocket Test Client”A test utility in utilities/websocket-client/ streams WAV file audio to the WebSocket server:
cd utilities/websocket-clientnpm run setup # Install dependencies (first time)npm run build # Build TypeScriptConfigure environment variables (export or .env file):
SAMPLE_RATE=8000BYTES_PER_SAMPLE=2CHUNK_SIZE_IN_MS=200CALL_FROM_NUMBER='LCA-Client'CALL_TO_NUMBER='+8001112222'AGENT_ID='TestAgent'LMA_ACCESS_JWT_TOKEN=<access_token>LMA_ID_JWT_TOKEN=<id_token>LMA_REFRESH_JWT_TOKEN=<refresh_token>Get the JWT tokens from an authenticated LMA user session. Then run:
npm run start -- --uri <WebSocket_Server_Endpoint> --wavfile <file.wav>The WebSocket server endpoint is in the CloudFormation stack Outputs.
Linting
Section titled “Linting”From lma-ai-stack/, the Makefile provides linting targets (requires CONFIG_ENV environment variable):
| Target | Tool | What it checks |
|---|---|---|
make lint-cfn-lint | cfn-lint | CloudFormation templates |
make lint-yamllint | yamllint | YAML syntax |
make lint-pylint | pylint | Python code (100 char lines) |
make lint-mypy | mypy | Python type annotations |
make lint-bandit | bandit | Python security |
make lint-validate | SAM CLI | Template validation |
Code style conventions:
- Python: Black formatter, Flake8, Pylint. 100-character line limit. Config in
.pylintrc,.flake8. - JavaScript/TypeScript: ESLint (airbnb-base) + Prettier. 120-character line limit, single quotes, trailing commas. Config in
.eslintrc.json,.prettierrc.
Continuous Integration
Section titled “Continuous Integration”Two pipelines run the same set of no-AWS checks:
| Pipeline | File | Triggers |
|---|---|---|
GitHub Actions Code Checks | .github/workflows/code-checks.yml | Pull requests to develop or main, and pushes to those branches |
GitLab code_checks | .gitlab-ci.yml | Every branch push and merge request |
GitLab nightly_integ_tests | .gitlab-ci.yml | A pipeline schedule only — see Scheduled Integration Tests |
Both take the Node.js version from .nvmrc at the repository root (22.23.2;
= 22.22.2 is required by jsdom 30). That file is the single pin — GitHub Actions reads it via
node-version-file, the GitLab job downloads the version it names, andmake setup-nodeinstalls it with nvm. The pipelines run, in order:
make setup-python && make setup-cli-devmake lint-cfn # cfn-lint on all CloudFormation templatesmake test-sdk && make test-cli # LMA SDK + CLI unit testsmake test-lambdas # Lambda unit suites (each dir isolated)make lint-ui-force && make test-ui-force # React UI eslint + vitestmake lint-typescript # tsc + eslint (transcriber, Virtual Participant)make test-vp && make test-vp-template # Virtual Participant unit + template testsmake test-ai-stack # AppSync contract + AI stack CFN invariantsmake test-integ-plumbing # Scheduled integ-run machinery (no AWS)make test-asr # ASR MicroVM runtime tests + ruffcd lma-websocket-transcriber-stack/source/app && npm ci && npm test && npm run smokecd lma-browser-extension-stack && npm install && CI=true npm test && CI=false npm run buildNone of these need AWS credentials or Docker. The local image builds
(make docker-build-check) do, so they are run manually. The integration tests
do too, and run on a nightly GitLab schedule against a long-lived stack —
make integ-tests remains the way to run them by hand, and
Scheduled Integration Tests covers the
scheduled run and the one-time setup it needs.
Line coverage is measured by make test-coverage, which is deliberately not part
of this pipeline — it reports numbers rather than enforcing a threshold, and runs
every suite. See Test Coverage.
The GitLab pipeline additionally
runs the security review job on merge requests targeting develop — see
Security Scanning.
Customization Entry Points
Section titled “Customization Entry Points”| What to customize | How | Docs |
|---|---|---|
| LLM summary prompts | DynamoDB or admin UI | Transcript Summarization |
| Chat shortcut buttons | Admin UI | Meeting Assistant |
| MCP server integrations | Admin UI | MCP Servers |
| Knowledge Base documents | S3 bucket or web crawling | Meeting Assistant |
| Bedrock Guardrails | CloudFormation parameter | Meeting Assistant |
| Transcript processing | Custom Lambda function | Lambda Hook Functions |
| Voice assistant prompts | DynamoDB or admin UI | Nova Sonic 2 Setup |
Contributing
Section titled “Contributing”See CONTRIBUTING.md for guidelines on reporting bugs, requesting features, and submitting pull requests.