Skip to content

Contribution guide

Thank you for your interest in contributing to data-director, a reference implementation of the Research Data Alliance's Data Director Agentic AI Blueprint.

The organisation-wide contribution guide applies here: when to open an RFC, the Developer Certificate of Origin sign-off (git commit -s) and the pull request workflow. Governance and the code of conduct are also organisation-wide. This file covers what is specific to this repository.

Contributing without writing code

Much of what the project needs is judgement rather than code: whether advice is right for a discipline, whether a decision suits an institution, whether a requirement is met. Each has an issue form, chosen when you open an issue:

  • Conformance review: you examined a Blueprint requirement, such as accessibility (C6) or the appropriateness of standards advice (R3), and found it met or not met. A maintainer records it in the review record on your instruction (the conformance report).
  • Spec feedback: a question about, or objection to, how one of the specifications says Data Director is built.
  • Blueprint reading: the project reads a Blueprint requirement differently from you, or misses one.
  • Feedback on advice: an agent's advice was wrong, incomplete or unhelpful, and you can say what good advice would have been.

Repository structure

This repository is organised as follow:

  • docs/ contains what governs every package: the Blueprint, the specifications (docs/specs/), the contract, the glossary, the requirements register and the review record. A package's own documents are in its own docs/ (harness/docs/, workbench/docs/)
  • app/ contains the Data Director app that people use (alpha); its browser shell in app/web needs Node 22 or later and npm (app/README.md)
  • sdk/ contains what agents and the harness share: the contract, evidence and the agent server
  • harness/ contains the governance every agent invocation goes through (System and boundaries)
  • workbench/ contains the development environment for building and testing sub-agents
  • agents/ contains one package per agent, including alpha-versioned experimental ones (agents/README.md)

Each package keeps to its own directory, so that it can later move to a repository of its own. Agent Skills, MCP servers and other resources that do not use the contract belong in their own repositories in the organisation. System and boundaries sets out both.

Changing the design

A specification states how one part is meant to work today, so a change to the design changes its spec in the same pull request, edited to say what is now true rather than amended. A change to a fixed format (the schema, the dd.* trace attributes, evidence canonicalisation or the outcome vocabulary) always changes a spec. An issue that proposes one carries the needs spec label. The history of the repository, its pull requests and its RFC issues are the record of how the design got here; the spec is the result.

Code style and testing

The Python packages use Python 3.14 and uv; app/web uses Node 22 and npm. uv run scripts/dev.py setup installs both sides and uv run scripts/dev.py doctor says what is wrong with a setup (README, "Quick start"). Follow the conventions of the surrounding code, and describe how you tested your change in the pull request description.

Every pull request runs .github/workflows/ci.yml, which ends in one check, CI passed, that passes only when every other job has. Each job can be run locally from the repository root:

Job Locally
Ruff (lint + format) uv run ruff check . && uv run ruff format --check .
mypy uv run mypy
pytest uv run pytest --json-report --json-report-file=.report.json
CONFORMANCE.md is current uv run python scripts/conformance_report.py --check (after pytest, which writes .report.json)
Generated schemas up to date uv run dd-gen-schema && git diff --exit-code -- sdk/src/dd_sdk/schema/generated/
Packages build and install alone uv build --all-packages -o dist && uv run python scripts/check_wheels.py dist
Agents as services (smoke) uv run python scripts/smoke_agents.py
Workbench viewer in a browser uv run playwright install chromium && uv run pytest workbench/browser_tests
App shell in app/web: npm ci && npm run lint && npm run typecheck && npm test && npm run build && npm run e2e
Links and citation file lychee --offline --include-fragments '**/*.md', uvx cffconvert --validate, uv run scripts/check_citation.py, scripts/check_todos.py and scripts/check_boundaries.py
Workflows uvx zizmor .github and actionlint
Developer Certificate of Origin every commit signed off by its author: git commit -s
Dependency review a new dependency with a known advisory of moderate severity or worse is refused

.github/workflows/accessibility.yml checks what people read and use against WCAG 2.2 AA, with axe-core and reflow at 320 CSS pixels, and ends in its own check, Accessibility passed:

Job Locally
Documentation site uv run --only-group docs mkdocs build --strict && uv run --only-group docs --only-group accessibility scripts/check_site_accessibility.py site
Workbench viewer uv run pytest workbench/browser_tests/test_viewer_accessibility.py

The app shell's accessibility checks run in the App shell job of ci.yml.

The pytest suite blocks the network and needs no credentials. CONFORMANCE.md is generated; regenerate it with the same two commands without --check. CodeQL (codeql.yml) analyses the Python, JavaScript and TypeScript code and the workflows, and audit.yml checks every locked dependency against the advisory databases each day. Dependabot proposes updates weekly.

Pull request titles and branch names

A pull request is squash-merged, so its title becomes the commit subject on main, and release-please reads that subject as a Conventional Commit to decide each package's next version and its changelog. names.yml checks every pull request and runs again when the title is edited:

  • the title is type(scope)!: summary. type is one of build, chore, ci, docs, feat, fix, perf, refactor, revert, style or test; (scope), usually the package (app, harness, sdk), and !, for a breaking change, are optional. The summary starts in lower case unless its first word is a name or acronym, has no closing full stop, and the whole title is at most 90 characters: feat(app): register every in-tree agent
  • the branch is lower-case words joined by hyphens, optionally grouped with slashes, in at most 60 characters: ci-faster, harness/run-store

Dependabot's and release-please's pull requests are exempt. Check a title and branch locally:

python3 scripts/check_names.py --title "feat(app): history tab" --branch "$(git branch --show-current)"

Keeping uv.lock current

uv.lock records every workspace package's version and dependencies, so any branch that changes a pyproject.toml changes it too, and two such branches conflict. The uv-lock pre-commit hook re-locks whenever a pyproject.toml changes, so the lock never lags behind and CI's locked check never fails for that reason. Install it once:

uv tool install pre-commit && pre-commit install

Never resolve a uv.lock conflict by hand. Take the base branch's file and lock again:

git checkout origin/main -- uv.lock && uv lock && git add uv.lock

then continue the rebase or merge. Release pull requests are re-locked by release-please.yml.

Releases

RELEASING.md describes the versioning policy, how release-please makes a release and what to do when it goes wrong. A pull request needs nothing more than a Conventional Commit title; release-please reads it.

Credit

Everyone who authors or co-authors a commit is cited as an author of the software. In your first pull request, add yourself to authors in the citation file, with your ORCID and affiliation if you have them:

  - given-names: Ada
    family-names: Lovelace
    email: ada@example.org
    affiliation: University of Example
    orcid: 'https://orcid.org/0000-0000-0000-0000'

scripts/check_citation.py runs in the "Links and citation file" job and lists anyone missing. It matches the email address of each commit's author, and of each Co-authored-by: trailer, against email, or the name against given-names and family-names. If you commit under several names or addresses, add a line to .mailmap that maps them to the one in the citation file. Bots and AI assistants are not cited; the project's AI usage statement discloses their use instead. Run it locally in a full clone:

uv run scripts/check_citation.py