Thanks for your interest in contributing! This guide covers the most common ways to help.
git clone https://github.com/your-org/workflow-verify.git
cd workflow-verify
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"pytest tests/ -vruff check src/ tests/
ruff format src/ tests/
mypy src/workflow_verify/ --ignore-missing-importsThis is the easiest way to contribute. Schemas live in src/workflow_verify/registry/schemas/ organized by category:
schemas/
├── common/ # Reusable building blocks (Person, Address, Money)
├── communication/ # Messaging schemas (Slack, Email, Webhook)
├── crm/ # CRM objects (Salesforce, HubSpot, CRMZero)
├── data/ # Data infrastructure (Postgres, Stripe, CSV)
└── enrichment/ # Data enrichment (Clearbit, Clay, Apollo)
Create a YAML file in the appropriate category directory:
# schemas/crm/my_crm_contact.yaml
name: MyCRMContact
description: Contact record from MyCRM
source: mycrm
fields:
- name: id
type: Text
description: Unique contact ID
- name: email
type: Email
description: Primary email address
- name: first_name
type: Text
description: First name
- name: last_name
type: Text
description: Last name
- name: created_at
type: DateTime
description: Creation timestampUse these type values:
| Type | Description |
|---|---|
Text |
Generic string |
Email |
Email address (subtype of Text) |
Url |
URL (subtype of Text) |
Phone |
Phone number (subtype of Text) |
Int |
Integer (subtype of Float) |
Float |
Floating-point number |
Bool |
Boolean |
Date |
Date |
DateTime |
Date with time |
Json |
Arbitrary JSON |
Any |
Any type (escape hatch) |
Fields can include optional validation:
- name: score
type: Int
description: Lead score
validate: "0 <= value <= 100"# Verify it loads
python -c "from workflow_verify import load_schema; s = load_schema('crm/my_crm_contact'); print(f'{s.name}: {len(s.fields)} fields')"
# Run the registry tests
pytest tests/test_registry.py -v
# Search for it
python -c "from workflow_verify import search_schemas; print([s.name for s in search_schemas('mycrm')])"- YAML file in the correct category directory
-
name,description,source, andfieldsare all present - Field types use valid
WFTypevalues -
pytest tests/test_registry.pypasses - Schema loads without errors
Dynamic resolvers fetch live schemas from service APIs. They live in src/workflow_verify/resolvers/. See hubspot.py or stripe.py for reference implementations.
A resolver must:
- Subclass
SchemaResolverfromresolvers/base.py - Set
service_name,supported_objects, andenv_var_names - Implement
async def resolve(self, object_type, credentials, include_custom) -> Schema - Be registered in
resolvers/__init__.py
- Keep PRs focused on a single change
- Include tests for new functionality
- Run the full test suite before submitting
- Follow existing code style (enforced by ruff)
Open an issue on GitHub.