This workspace provides a Python package soa_builder with APIs to create a Schedule of Activites for Clinical Studies.
This project now includes a submodule for USDM JSON validation with the USDM_API_v4.0.0.json schema.
In order to clone the repository with the new submodule, use the command:
> git clone --recurse-submodules https://github.com/pendingintent/soa-workbench.gitOnce the repository has been cloned locally, in order to ensure the submodule is up-to-date, use the commands:
> cd cdisc-json-validation
> git pull
# or use the command for updating all registered submodules
> git submodule update --remoteThis will ensure the submodule is always up-to-date.
Recommended: editable install for development.
> python3 -m venv .venv
> source .venv/bin/activate
> pip install -r requirements.txt
> pre-commit install
> pre-commit run --all-filesAll runtime settings are controlled through config.env in the project root.
The file is loaded automatically at startup via python-dotenv.
Edit config.env before starting the server:
# Server
SOA_BUILDER_HOST=0.0.0.0
SOA_BUILDER_PORT=8008
# Database (relative to working directory)
SOA_BUILDER_DB=soa_builder_web.db
# Logging — set to 1 for DEBUG output
SOA_BUILDER_DEBUG=0
# Output directory for normalized SOA files
SOA_BUILDER_NORMALIZED_ROOT=normalized
# CDISC Library Cosmos v2 API base URL
CDISC_BC_API_BASE_URL=https://api.library.cdisc.org/api/cosmos/v2
# Set to 1 to skip all remote CDISC Library API calls (offline mode)
CDISC_SKIP_REMOTE=0
# Cache TTL in seconds for all CDISC Library API responses (default: 1 hour)
SOA_BUILDER_CACHE_TTL=3600
# HTTP timeout in seconds for outbound CDISC Library API requests
CDISC_REQUEST_TIMEOUT=15
# Set to 0 to disable eager BCP property loading at startup
SOA_EAGER_BCP_POPULATION=1CDISC API credentials —
CDISC_API_KEYandCDISC_SUBSCRIPTION_KEYare secrets and must not be placed inconfig.env. Set them in your shell environment instead:export CDISC_API_KEY=your-key-hereThe server will pick them up automatically via the process environment.
| Variable | Default | Description |
|---|---|---|
SOA_BUILDER_HOST |
0.0.0.0 |
IP address the server binds to |
SOA_BUILDER_PORT |
8008 |
TCP port the server listens on |
SOA_BUILDER_DB |
soa_builder_web.db |
SQLite database file path |
SOA_BUILDER_DEBUG |
0 |
Set 1 for DEBUG-level logging |
SOA_BUILDER_NORMALIZED_ROOT |
normalized |
Root dir for normalized SOA output |
CDISC_BC_API_BASE_URL |
https://api.library.cdisc.org/api/cosmos/v2 |
CDISC Cosmos v2 API base URL |
CDISC_SKIP_REMOTE |
0 |
Set 1 to skip remote CDISC API calls |
CDISC_CONCEPTS_JSON |
(empty) | Override biomedical concepts (JSON file path or inline JSON) |
CDISC_SDTM_SPECIALIZATIONS_JSON |
(empty) | Override SDTM specializations (JSON file path or inline JSON) |
SOA_BUILDER_CACHE_TTL |
3600 |
Cache TTL (seconds) for all CDISC API responses |
CDISC_REQUEST_TIMEOUT |
15 |
HTTP timeout (seconds) for CDISC Library API requests |
SOA_EAGER_BCP_POPULATION |
1 |
Set 0 to enable lazy BCP property loading |
CDISC_API_KEY |
(shell env) | CDISC Library API key — set in shell, not config.env |
CDISC_SUBSCRIPTION_KEY |
(shell env) | CDISC Library subscription key — set in shell, not config.env |
soa-builder-web # starts uvicorn on the host/port set in config.envOr manually:
uvicorn soa_builder.web.app:app --reload --port 8008HTML UI:
- Open http://localhost:8008/ in a browser (or the port set in
config.env). - Create a new Schedule of Activities for a study or access an existing one.
- When a study is chosen, additional navigation links are available in the navigation menu that are unique to the Study context.
- More options and parameters for configuring the USDM classes are available through these navigation links.
- Add Scheduled Activity instances (columns) and activities (rows) to create an SoA matrix on the edit page for a Study; click cells to toggle status (blank -> X -> blank). 'O' values are not surfaced in the UI; clearing removes the cell row.
- Use export buttons (to be added) for XLSX output of the Matrix.
- View avialable biomedical concepts via the "Biomedical Concepts" navigation link to render a table of concept codes, titles and API links (cached; force refresh available).
- View available data set specializations via the "SDTM Dataset Specializations" navigation link to render a table of specializations and API links to view associated concepts (cached; force refresh available).
CDISC Library API Access:
- The concepts list and detail pages call the CDISC Library API.
- Set one (or both) of:
CDISC_SUBSCRIPTION_KEY,CDISC_API_KEY. - The server will send all of these headers when possible:
Ocp-Apim-Subscription-Key: <key>Authorization: Bearer <key>(whenCDISC_API_KEYprovided)api-key: <key>(legacy fallback)
- If only one key is defined it is reused across header variants.
- Directly opening the API URL in the browser will 401 because the browser does not attach the required headers; use the internal detail page or an API client (curl/Postman) with the headers above.
Run unit tests:
pytest- Tests run against a separate SQLite file to avoid touching your local/prod data.
- Default path:
soa_builder_web_tests.dbin the repo root. Override with env varSOA_BUILDER_DB. - A pytest session fixture removes any stale test DB/WAL/SHM files at start to prevent I/O errors.
- Manually clear the test DB before a run if needed:
rm -f soa_builder_web_tests.db soa_builder_web_tests.db-wal soa_builder_web_tests.db-shmFull API Documentation: See
README_endpoints.mdfor complete endpoint reference with curl examples, request/response schemas, and usage patterns.Endpoint Catalog: See
docs/api_endpoints.csvfor sortable/filterable list of all 165+ endpoints.
Export USDM-compliant JSON for integration with external systems:
# Use the USDM generator scripts directly
python -m usdm.generate_usdm 1 -o study_usdm.json
python -m usdm.generate_activities 1 -o activities.json
python -m usdm.generate_encounters 1 -o encounters.json
python -m usdm.generate_study_epochs 1 -o epochs.json
# See src/usdm/ for all generator scriptsThe workbench ships an MCP (Model Context Protocol) server that exposes SoA data as tools for Claude agents. This enables workflows such as "analyze this protocol PDF and populate the visit schedule" without copy-paste.
The server is registered in .mcp.json and starts automatically when Claude Code loads the project. Confirm it is listed with /mcp in a Claude session.
The soa-mcp command is installed alongside soa-builder-web:
pip install -e .
soa-mcp # starts the MCP stdio server (for manual testing)The server reads SOA_BUILDER_DB from the environment (falls back to soa_builder_web.db). No web server needs to be running — it accesses the SQLite database directly.
| Tool | Description |
|---|---|
list_soas |
List all Schedules of Activities |
create_soa |
Create a new SoA; returns soa_id |
get_soa |
Get SoA metadata by id |
list_visits |
List visit definitions ordered by order_index |
create_visit |
Add a visit (name, label, type) |
list_activities |
List activities ordered by order_index |
create_activity |
Add an activity (name, label, description) |
assign_instance_activity |
Mark an activity at a ScheduledActivityInstance; use get_soa_matrix for ids |
get_soa_matrix |
Return the visits × activities grid (instances, activities, cells) |
get_usdm_json |
Generate a USDM component as JSON (full, encounters, activities, biomedical_concepts, etc.) |
get_define_json |
Generate a Define-JSON document (requires sdtmct date and CDISC_API_KEY) |
The .mcp.json entry uses the absolute path to the venv console script:
"soa-workbench": {
"command": "/path/to/.venv/bin/soa-mcp",
"args": [],
"env": {
"SOA_BUILDER_DB": "/path/to/soa_builder_web.db"
}
}Update the paths to match your environment after cloning.
- Database: SQLite with WAL mode (production) or DELETE mode (tests)
- Test Isolation: Tests use
soa_builder_web_tests.db(set viaSOA_BUILDER_DBenv var) - Production Config: Set
SOA_BUILDER_DBenvironment variable for persistent DB path - USDM Generators: Python scripts in
src/usdm/transform database state → USDM JSON artifacts