Skip to content

Contributing to GENEALOGIX ​

Thank you for your interest in contributing to GENEALOGIX! Whether you're a genealogist, developer, or both, we welcome contributions of all kinds.

Table of Contents ​

How Can I Contribute? ​

For Genealogists ​

  • Improve Examples: Add real-world genealogy scenarios
  • Documentation: Clarify genealogical concepts and best practices
  • Test Cases: Contribute edge cases from your research experience
  • Use Case Reports: Share how GENEALOGIX works (or doesn't) for your needs

For Developers ​

  • Bug Fixes: Fix issues in the CLI tool or validation logic
  • New Features: Implement accepted proposals from GitHub issues
  • Performance: Optimize validation speed and memory usage
  • Tooling: Build integrations, converters, or utilities

For Everyone ​

Good First Issues ​

Browse issues labeled good first issue for beginner-friendly tasks.

What to expect when you pick one up:

  • Each good first issue has clear acceptance criteria in the issue body. If something is ambiguous, comment on the issue before you start.
  • Maintainers respond to questions in issue comments as bandwidth allows — ask before sinking time into a large change.
  • First PRs typically receive substantive review feedback (see Review Process for response time).

Development Environment Setup ​

Prerequisites ​

  • Go 1.27+ (install) — the project uses Go 1.27 in go.mod
  • Git (install)
  • Node.js — for website builds (npm install in website/) and schema validation (npm ci --prefix specification)

Dev Container ​

The easiest way to get started is with the included Dev Container:

bash
# VS Code: Install the "Dev Containers" extension, then:
# Ctrl+Shift+P → "Dev Containers: Reopen in Container"

# GitHub Codespaces: Click "Code" → "Codespaces" → "Create codespace on main"

The container includes Go, Node.js, golangci-lint, and lefthook (pre-commit hooks installed automatically at create time). goreleaser and syft are not installed in the container — they're only needed for make release-snapshot (maintainer/release work) and should be installed manually on demand (goreleaser, syft).

Manual Setup ​

bash
# Fork and clone
git clone https://github.com/YOUR_USERNAME/glx.git
cd glx
git remote add upstream https://github.com/genealogix/glx.git

# Install dependencies
make install-deps

# Build and verify
make build
./bin/glx --help

# Run tests
make test

# (Optional) Install schema validation tooling
npm ci --prefix specification
make check-schemas

Install lefthook to run lint checks on staged files before each commit:

bash
make install-hooks

Both jobs lint the staged content, not the working copy, with the settings CI uses (scripts in scripts/hooks/):

  • When Go files are staged, golangci-lint runs on the packages your branch changes and reports issues new since the branch point with origin/main, mirroring CI's only-new-issues: true. It requires the version pinned in .golangci-lint-version and tells you how to install it if yours differs.
  • When .js, .mjs, .cjs or .vue files under website/ are staged, eslint runs on them with --max-warnings 0, like npm run lint. Run make install-deps first so website/node_modules exists.

Skip the hooks for one commit with git commit --no-verify, which works in every shell. LEFTHOOK=0 git commit ... also works in a POSIX shell (in PowerShell, set $env:LEFTHOOK=0 and clear it afterwards with Remove-Item Env:LEFTHOOK).

Makefile Reference ​

TargetDescription
make install-depsInstall Go modules and npm packages
make install-hooksInstall lefthook pre-commit hooks (one-time)
make testRun all tests
make test-verboseRun tests with verbose output
make test-coverageRun tests with coverage report
make lintRun Go and website linters
make lint-fixRun linters with auto-fix
make fmtFormat Go and website code
make vulncheckRun govulncheck (pinned via ci-tools/go.mod)
make buildBuild CLI and website
make build-cliBuild just the glx binary to bin/
make check-schemasValidate JSON schema files
make check-linksValidate internal markdown links
make release-snapshotBuild cross-platform binaries locally
make cleanRemove build artifacts

Development Workflow ​

Fork and Direct-Push ​

External contributors use the fork workflow:

bash
git fetch upstream
git checkout main
git merge upstream/main
git checkout -b feat/my-feature
# ... make changes ...
git push origin feat/my-feature
# Open PR from your fork

Org members can push branches directly:

bash
git checkout main
git pull
git checkout -b feat/my-feature
# ... make changes ...
git push -u origin feat/my-feature
# Open PR

Branch Naming ​

Use conventional prefixes:

text
feat/short-description
fix/short-description
docs/short-description
chore/short-description

Commit Messages ​

Follow Conventional Commits. Valid types: feat, fix, docs, chore, refactor, test, perf, ci.

text
feat: Add GEDCOM 7.0 EXID support
fix: Handle nil map in merge
docs: Update quickstart guide

Every commit must also carry a Signed-off-by trailer — see Developer Certificate of Origin (DCO) for how to add one and what you're attesting to.

Changelog Conflicts ​

CHANGELOG.md is marked merge=union in .gitattributes. When your branch and main both add entries, a local git merge main (or git rebase main) keeps both sides instead of leaving conflict markers. union is a git built-in, so it works in every clone with no git config step — unlike the optional merge=glx driver for .glx files described in docs/merge-driver.md.

Review the merged result anyway — union keeps every line from both sides without understanding the file:

  • Across a release boundary it can misfile your entry. If main promoted ## [Unreleased] to a released version heading while your branch added an entry under it, union keeps both and your entry ends up inside the released section, which must never be edited. After merging main following a release, check that your entries sit under ## [Unreleased]; the reliable fix is to restore the file from the freshly fetched upstream ref — git checkout upstream/main -- CHANGELOG.md on a fork, origin/main on a direct clone — and then re-add your branch's entries. Don't restore from a local main branch unless you have just updated it; a stale one would discard the release you are merging in.
  • Entry order and duplicated headings may still need a tidy-up when both sides restructured the same region.

GitHub's "Update branch" button — and the auto-update bot that keeps PR branches current — merge server-side, and the GitHub merge API does not honor .gitattributes merge drivers. If GitHub reports a conflict in CHANGELOG.md only, resolve it by merging main locally and pushing:

bash
# Fork workflow: the canonical repo is `upstream`, your PR branch lives on `origin`.
git fetch upstream
git merge upstream/main   # union resolves CHANGELOG.md
git push origin HEAD

# Org members pushing branches directly: the canonical repo is `origin`.
git fetch origin
git merge origin/main
git push

Testing ​

Prefer using the Makefile to run tests for consistency. go test directly is fine for targeted runs.

bash
make test              # Run all tests
make test-verbose      # Verbose output
make test-coverage     # Coverage report
make check-schemas     # Validate JSON schemas

Writing Tests ​

  • Unit tests for all new functions
  • Integration tests for full conversion paths
  • E2E tests for CLI commands
  • Test files live alongside source: foo.go → foo_test.go
  • GEDCOM test files: glx/testdata/gedcom/
  • Validation test fixtures: glx/testdata/valid/ and glx/testdata/invalid/

Coverage ​

CI uploads coverage to Codecov on every PR and push to main. Two checks gate merges:

  • Project coverage must not drop more than 1% from the current baseline.
  • Patch coverage (lines changed by the PR) must be at least 80% covered.

Run make test-coverage locally to preview the total project coverage before pushing (the patch number is computed by Codecov from the PR diff and isn't reproducible locally).

CI Checks ​

Every PR runs these checks automatically:

CheckWhat it does
CI / test-conformanceGo tests for glx/ and go-glx/ packages
codecov/project, codecov/patchProject coverage may drop by at most 1%; patch coverage (new code) must be ≥80%
CI / validate-schemasJSON schema validation
CI / validate-examplesAll example archives pass glx validate
Lint Markdown / markdownlint-cli2Structural markdown validation for specification/, docs/, root *.md
Lint Website / eslinteslint over website/.vitepress JS/Vue (the website half of make lint)
Securitygosec, govulncheck, and npm audit
Workflow Lint / zizmor, Workflow Lint / actionlintSecurity and correctness analysis of GitHub Actions workflows; runs only when a PR touches .github/workflows/, .github/dependabot.yml or the tools' pins. Run locally with make lint-workflows
lint-pr-titlePR title follows conventional commits format
dependency-reviewBlocks PRs introducing vulnerable dependencies

All checks must pass before merge.

Documentation Standards ​

Writing Style ​

  • Specification docs: Clear, precise, professional language. Define technical terms on first use.
  • User docs: Friendly, step-by-step instructions with real-world examples.

Link between markdown files with relative repository paths that include the .md extension. That is the form GitHub renders; the website maps the same links through its rewrites table (website/.vitepress/relative-links.js), so one form serves both.

  • Good: [Person Entity](4-entity-types/person.md), [Quickstart](../docs/quickstart.md)
  • Bad: [Person Entity](4-entity-types/person) (GitHub does not append .md)
  • Bad: [Quickstart](/quickstart) (a website route; on GitHub it resolves to github.com/quickstart)

make check-links enforces this for specification/, docs/, the root *.md files and .github/SUPPORT.md. Absolute routes are fine in website/ itself, which is never read on GitHub.

Markdown Linting ​

Markdown is validated by markdownlint-cli2 in CI (see Lint Markdown above). The configuration lives in .markdownlint-cli2.jsonc at the repo root. Run it locally before pushing:

bash
npx --yes markdownlint-cli2
# auto-fix what can be fixed (whitespace, blank-line rules):
npx --yes markdownlint-cli2 --fix

Genealogical Standards ​

Submitting Changes ​

Pull Request Process ​

  1. Create an issue first for non-trivial changes
  2. Follow the PR template
  3. Ensure all CI checks pass
  4. Add tests for new features and bug fixes
  5. Update documentation if behavior changes
  6. Update CHANGELOG.md for user-facing changes (add to the unreleased section). Every entry must include an issue or PR reference — e.g. (#123), Fixes #123, Closes #123, (PR #456)

Review Process ​

  • Maintainers will review PRs within 3-5 business days
  • Address review comments promptly
  • Be open to feedback and iteration

Contributor Path ​

GLX keeps the contributor structure deliberately lightweight. There is no formal application process; progression is recognition of an established pattern.

  • First-time contributor — you've submitted (or are submitting) your first PR. No special permissions; your change is reviewed like any other PR.
  • Regular contributor — multiple merged PRs across the codebase. May be asked to review PRs in areas you're familiar with. Changes still go through normal review.
  • Maintainer — commit access, release authority, and triage responsibility. Invited by current maintainers based on sustained contributions and engagement. Invitation only.

All contributors at every level are expected to follow the Code of Conduct.

Developer Certificate of Origin (DCO) ​

GENEALOGIX uses the Developer Certificate of Origin (DCO) 1.1 — the same lightweight attestation used by the Linux kernel, CNCF projects, and many other open-source projects. Rather than requiring a heavier Contributor License Agreement, there is no separate document to sign and no CLA bot to negotiate with. By signing off each commit, you attest that you wrote the change (or have the right to submit it) and that it can be contributed under the project's Apache 2.0 license. The DCO is an attestation of your right to contribute the code — it is not a copyright assignment. You retain copyright in your contribution. There is no automated DCO check today; sign-offs are trusted and verified manually during review.

Signing off ​

Add a Signed-off-by trailer to every commit using the -s (or --signoff) flag:

bash
git commit -s -m "feat: Add GEDCOM 7.0 EXID support"

This appends a line to the commit message using the identity from git config user.name and git config user.email:

text
Signed-off-by: Your Name <[email protected]>

Use the same name and email you use for other contributions so maintainers can reach you about your change. If user.name or user.email are wrong for this repository, set them locally before committing:

bash
git config user.name "Your Name"
git config user.email "[email protected]"

Fixing a missing sign-off ​

If you forgot -s on your most recent commit:

bash
git commit --amend --signoff --no-edit
git push --force-with-lease

For a range of commits (e.g., the last 3):

bash
git rebase --signoff HEAD~3
git push --force-with-lease

Only force-push branches you own. If others are collaborating on the branch, coordinate with them before rewriting history to avoid disrupting their work.

The DCO text ​

text
Developer Certificate of Origin
Version 1.1

Copyright (C) 2004, 2006 The Linux Foundation and its contributors.

Everyone is permitted to copy and distribute verbatim copies of this
license document, but changing it is not allowed.


Developer's Certificate of Origin 1.1

By making a contribution to this project, I certify that:

(a) The contribution was created in whole or in part by me and I
    have the right to submit it under the open source license
    indicated in the file; or

(b) The contribution is based upon previous work that, to the best
    of my knowledge, is covered under an appropriate open source
    license and I have the right under that license to submit that
    work with modifications, whether created in whole or in part
    by me, under the same open source license (unless I am
    permitted to submit under a different license), as indicated
    in the file; or

(c) The contribution was provided directly to me by some other
    person who certified (a), (b) or (c) and I have not modified
    it.

(d) I understand and agree that this project and the contribution
    are public and that a record of the contribution (including all
    personal information I submit with it, including my sign-off) is
    maintained indefinitely and may be redistributed consistent with
    this project or the open source license(s) involved.

Proposing Major Changes ​

Proposal required (via GitHub Issue) for:

  • Changes to core data model or entity types
  • New required fields or breaking changes
  • Changes to validation rules or file format

No proposal needed for:

  • Bug fixes, documentation improvements, new examples, minor clarifications

Proposal Workflow ​

  1. Create Issue: Describe the proposed change
  2. Discussion: Community reviews and comments (minimum 7 days for spec changes)
  3. Decision: Maintainers accept, reject, or request changes
  4. Implementation: After acceptance, submit a PR

Architecture Decision Records (ADRs) ​

When to write an ADR:

  • Changes to the core data model, entity types, or validation rules
  • New constraints on the library (e.g., "go-glx must never do X")
  • Choice of a major dependency, format, or protocol
  • Any decision you expect to still be referenced a year from now

For routine bug fixes, documentation improvements, and minor clarifications, no ADR is needed — a regular issue and PR are sufficient.

See docs/decisions/ for the ADR index, template, format, and proposal workflow.

AI-Generated Contributions ​

AI is welcome. Humans are accountable.

GLX is a small project with limited maintainer capacity. Every issue, PR, and comment costs human time to triage. These guidelines exist to protect that time.

All contributions must reflect genuine understanding of the GLX spec and codebase. Contributors are fully responsible for everything they submit, regardless of how it was produced. If you cannot explain your change and respond to feedback about it, do not submit it.

Autonomous Agents and Bots ​

Autonomous AI agents (OpenClaw, bounty bots, or similar) are not permitted to open issues, submit PRs, or post comments on any repository in the genealogix org. This includes agents acting on behalf of a human who is not actively supervising and reviewing each interaction.

Contributions that appear to be bot-generated will be closed without review and the account may be blocked.

PRs and Issues ​

  • Contributors are limited to 3 open PRs at a time across all genealogix repositories
  • Address all review comments on existing PRs before opening new ones

AI-Assisted Development ​

Using AI tools (Copilot, Claude, ChatGPT, etc.) as part of your workflow is fine. The bar is the same as any contribution: you understand the problem, you've tested the change, and you can engage with review feedback.

Contributors SHOULD disclose substantial AI assistance via a commit trailer:

text
Assisted-by: Claude <[email protected]>

Co-authored-by trailers added automatically by AI coding tools are also acceptable.

Never put a link to an AI tool's private session, chat, or project thread in a commit message, PR title or body, review comment, code comment, or any other pushed artifact. URLs such as https://claude.ai/code/session_... and https://claude.ai/code/project/... resolve only for the operator who ran the tool, so they are dead ends for every reader and they disclose where the work happened. The Claude-Session: trailer is the same rule.

Tool-generated attribution blocks do not belong in a PR body either, link or no link: no "Requested by name" credit line, no machine-readable marker comment, no "Generated with tool" footer. Git records who authored the commits and the PR records who opened it, so the block adds nothing a reader cannot already see.

Both rules hold even when the tool's own boilerplate supplies the line — strip it before pushing.

This is about attribution a tool adds for itself. The trailers this project asks for are unaffected: Signed-off-by is required on every commit by the DCO, and Assisted-by: above is how to disclose AI assistance. Both stay, and neither needs a link.

Enforcement ​

Maintainers will close low-quality or bot-generated contributions without detailed explanation. Repeated violations will result in the account being blocked from the org.

We follow the Linux Foundation Generative AI Policy. Contributors must ensure AI tool terms do not conflict with the project's license.

Code of Conduct ​

We are committed to providing a welcoming and inclusive environment. Please read and follow our Code of Conduct.

Security ​

To report a vulnerability, see our Security Policy.

Building for Release ​

Releases use GoReleaser (automated in CI on tag push):

bash
# Test release build locally (requires the goreleaser and syft CLIs)
make release-snapshot

syft is required because .goreleaser.yml generates an SPDX-JSON SBOM for each release archive; without it on PATH the snapshot build fails at the SBOM step. Install it from https://github.com/anchore/syft#installation (in CI, release.yml installs it via anchore/sbom-action/download-syft).

cosign is not required: the target passes --skip=sign. --snapshot on its own implies only --skip=announce,publish,validate, so the signs: stanza would otherwise still run and either fail with cosign: executable file not found or block on an interactive keyless OIDC prompt. Release signing is exercised by release.yml on a real tag push, not by the snapshot target.

Questions? ​


Thank you for contributing to GENEALOGIX!

Licensed under Apache License 2.0