Contributing to LinkForge

Thank you for your interest in contributing to LinkForge! This guide will help you get started.

Table of Contents

Code of Conduct

Be respectful, inclusive, and professional. We’re all here to build great robotics tools together.

Getting Started

Prerequisites

  • Python 3.11+

  • Blender 4.2+

  • Git

  • just (Command Runner)

    • macOS: brew install just

    • Linux: sudo apt install just (or via snap / cargo)

    • Windows: choco install just or scoop install just

    • Universal: cargo install just (requires Rust)

  • uv (Python package manager) - Install: curl -LsSf https://astral.sh/uv/install.sh | sh

Fork and Clone

# Fork the repository on GitHub, then:
git clone https://github.com/YOUR_USERNAME/linkforge.git
cd linkforge

Development Setup

1. Install Dependencies

# Install everything (deps + pre-commit hooks)
just install

2. Verify Setup

# Run tests to verify everything works
just test

# Run linter and type checker
just check

# Build extension
just build

Project Structure

linkforge/
├── core/                  # Core Robotics Logic (pip package)
│   └── src/linkforge/core/
├── platforms/
│   └── blender/           # Blender Extension (.zip)
├── tests/                 # Test Suite (unit + integration)
├── examples/              # Example URDF/XACRO files
└── pyproject.toml         # Workspace config

See ARCHITECTURE for detailed architecture diagrams.

Development Workflow

        graph LR
    A[Fork & Clone] --> B[Feature Branch]
    B --> C[Code & Test]
    C --> D[pre-commit Checks]
    D --> E[Pull Request]
    E --> F{Review}
    F -- Fixes --> C
    F -- Approved --> G[Merge to main]
    G --> H[Automated Release PR]
    H --> I[Tag & Release]
    

1. Create a Feature Branch

git checkout -b feature/your-feature-name

2. Make Changes

  • Write code following our Code Style

  • Add tests for new functionality

  • Update documentation as needed

3. Run Quality Checks

# Run all tests (Core + Blender)
just test

# Run specific tiers
just test-core                 # Fast core logic (unit + integration)
just test-unit-blender         # Mocked platform logic unit tests
just test-integration-blender  # Full Blender integration tests

# Run linter and type checker
just check

# Fix linting issues automatically
just fix

4. Live Testing in Blender (Development Mode)

LinkForge uses a Development Junction system to link your workspace directly into Blender without needing to build and re-install packages.

# 1. Establish the link (Run once)
just develop

# 2. Open Blender
# 3. Edit > Preferences > Extensions
# 4. Search for "LinkForge" and Enable it

Any changes you make to the .py files in your editor will be instantly available in Blender (you only need to restart Blender or reload the extension).

5. Testing the Release (Optional)

If you want to verify the final user experience (including bundled wheels):

# 1. Build the production ZIPs
just build

# 2. In Blender: Edit > Preferences > Extensions
# 3. Dropdown (⌄) > Install from Disk
# 4. Select dist/linkforge-blender-x.x.x-macos_arm64.zip

6. Commit Changes

git add .
git commit -s -m "feat: add your feature description"

Commit Message Format:

  • feat: New feature

  • fix: Bug fix

  • docs: Documentation changes

  • test: Test additions/changes

  • refactor: Code refactoring

  • perf: Performance improvements

  • chore: Maintenance tasks

Testing

Running Tests

LinkForge uses a Tiered Testing Architecture to balance speed and fidelity:

Tier

Command

Scope

Core

just test-core

Models, Kinematics, Parsers (Zero-deps)

Logic

just test-unit-blender

Blender Adapters & Math (Mocked bpy)

Integration

just test-integration-blender

Real Scene Interaction (Real Blender)

See Automated Testing for our full strategy and coverage metrics.

To run specific tests or categories:

# Run with coverage (Combined report)
just coverage

# Run specific core test file (manual)
uv run pytest tests/unit/core/test_robot.py

# Run specific Blender integration test file (manual)
uv run python scripts/blender_launcher.py tests/integration/platforms/blender/test_roundtrip.py

Manual QA (Mandatory)

For features involving UI, viewport transforms, or complex exports, automated tests are not enough. Contributors must follow and pass the Manual QA Protocol before submitting a PR.

  • Objective: Ensure export validity (URDF/XACRO standards), correct physics calculations, and UI stability across macOS, Windows, and Linux.

  • Protocol: Follow the 7-Phase checklist in docs/testing/manual_qa.md.

Writing Tests

Unit Test Example

def test_link_creation():
    """Test creating a link with valid parameters."""
    link = Link(
        name="test_link",
        visuals=[],
        collisions=[],
        inertial=Inertial(mass=1.0, inertia=InertiaTensor.stability_floor())
    )
    assert link.name == "test_link"
    assert link.inertial.mass == 1.0

Round-Trip Test Example

def test_sensor_roundtrip():
    """Test sensor origin survives import-export cycle."""
    # Create robot with sensor
    robot = Robot(
        name="test",
        initial_links=[Link(name="base_link")],
        initial_sensors=[
            Sensor(
                name="test_camera",
                type=SensorType.CAMERA,
                link_name="base_link",
                camera_info=CameraInfo(),
                origin=Transform(xyz=(0.1, 0.0, 0.2))
            )
        ]
    )

    # Export to URDF
    generator = URDFGenerator()
    urdf = generator.generate(robot)

    # Re-import
    from linkforge.core import URDFParser
    robot2 = URDFParser().parse_string(urdf)

    # Verify sensor origin preserved
    assert robot2.sensors[0].origin == robot.sensors[0].origin
  • Unit Tests (tests/unit/): Test individual functions/classes in isolation, split into core/ and platforms/.

  • Integration Tests (tests/integration/): Test full workflows and round-trips, split into core/ (logic, parsers) and platforms/ (Blender-specific).

[!TIP] Use Central Fixtures: Always use the examples_dir fixture from tests/conftest.py when accessing example URDFs. Avoid hardcoding relative paths like ../../examples.

We follow a Tiered Mocking Strategy based on the level of interaction:

  1. Platform Logic Tests (unit/platforms/): Prefer Mocks.

    • For math and transformation logic in adapters, use unittest.mock to verify inputs/outputs.

    • This allows for sub-second developer loops without booting Blender.

  2. Integration Tests (integration/platforms/): Prefer Real Data.

    • For scene manipulation and UI operators, use a real (headless) Blender instance.

    • Use bpy.ops.object.empty_add() to create real objects in your test fixtures.

    • Use the blender_clean_scene fixture to ensure environment isolation.

  3. Core Tests (unit/core/): Zero Dependencies.

    • Instantiate real Robot, Link, or Joint objects.

    • Mock only for external edge cases: Filesystem failures or missing optional dependencies.

Debugging in Blender

from linkforge.core import get_logger
logger = get_logger(__name__)
logger.error(f"Debug: {variable}")

# View in Blender Console (Window > Toggle System Console)

Code Style

Python Style Guide

Documentation Standards (Lean Google Style)

We follow a Lean Google Style for documentation. Every module and class must be documented to provide high-level context and component breakdowns:

  1. Module Headers: Summarize the purpose and categorize key components (Models, Validators, Utilities).

  2. Concise Summaries: Focus on intent and physical implications rather than just restating the signature.

  3. Core Components: Use a structured list in module docstrings to identify the main actors.

"""Module title.

Brief high-level summary of role in the IR.

Core Components:
    - ComponentA: Brief role description.
    - ComponentB: Brief role description.
"""

“Physics as Truth” Design Principle

LinkForge follows a strict Physics as Truth philosophy. The Intermediate Representation (IR) is not just a data structure; it is a physical model that must remain stable and plausible at all times.

  • Strict Validation: All models (Link, Joint, Sensor) must implement __post_init__ guardrails for physical properties (e.g., non-negative mass, normalized axes, valid LIDAR ranges).

  • Orchestrated Checks: Global consistency (cycles, connectivity, ros2_control limits) is enforced by the RobotValidator.

  • Fail Fast: We prefer a RobotValidationError at construction time over a physics engine crash at runtime.

# Good
def parse_float(text: str | None, default: float | None = None) -> float:
    ...

# Bad
def parse_float(text, default=None):
    ...

Linting Configuration

Our project rigorously enforces code quality using ruff. The definitive configuration (including line length, target version, and active rule sets) is maintained centrally in pyproject.toml. Please refer to the [tool.ruff.lint] section in that file for the current active and ignored rules.

Pre-commit Hooks

Pre-commit automatically runs on git commit:

  • ruff check - Linting (with auto-fix)

  • ruff format - Code formatting

  • conventional-pre-commit - Enforces conventional commit messages

  • codespell - Catches common typos in code and docs

  • Standard file checks - trailing whitespace, EOF newline, YAML/TOML/JSON validation, large files, merge conflicts, etc.

Submitting Changes

Developer Certificate of Origin (DCO)

All contributions to this project must be accompanied by a Developer Certificate of Origin (DCO) sign-off. This ensures that you have the right to submit the code under the project’s open-source license.

To sign off on a commit, simply use the -s flag when committing: git commit -s -m "Your descriptive commit message"

This will automatically add the following line to your commit message: Signed-off-by: Your Name <your.email@example.com>

Pull Request Process

  1. Push your branch

    git push origin feature/your-feature-name
    
  2. Create Pull Request

    • Go to GitHub and create a PR

    • Fill out the PR template

    • Link any related issues

  3. Check Pull Request Status

    • Ensure the CI pipeline passes (GitHub Actions).

    • Once you create the PR, follow the automated checklist provided in the PR description template. This ensures all standards (tests, linting, quality) are met before maintainer review.

  4. Code Review

    • Address review comments

    • Keep commits clean and logical

    • Squash commits if requested

  5. Merge

    • Maintainer will merge once approved

    • Your contribution will be in the next release!

PR Title Format

Use conventional commits:

  • feat: Add support for new sensor type

  • fix: Correct sensor origin export

  • docs: Update architecture diagrams

  • test: Add round-trip tests for transmissions

Release Process

LinkForge uses Release Please to automate versioning and changelogs.

  1. Automation: When code is merged into main, Release Please will automatically create (or update) a “Release PR”.

  2. Versioning: This PR will contain a version bump in pyproject.toml, blender_manifest.toml, CITATION.cff, and an updated CHANGELOG.md based on your commit messages.

  3. Merging: Once a maintainer merges this Release PR, a GitHub Tag and Release are automatically created.

  4. Distribution: The release-please.yml workflow will then build the extension .zip and attach it to the GitHub Release.

Release Standards

To maintain a professional and consistent appearance:

  • Tagging: Always use simple v prefixed tags (e.g., v1.3.0). This is handled automatically by the configuration.

  • Release Titles: Follow the format v1.x.x: [Major Highlight]. For example: v1.3.0: Performance & Control Refinement.

  • Changelog: Use the project’s custom sections (🚀 Features, 🐞 Bug Fixes, etc.) to keep notes organized.

[!NOTE] This is why Conventional Commits are required. Without them, the release automation cannot determine if a change should bump the MAJOR, MINOR, or PATCH version.

Technical Considerations

To maintain LinkForge’s status as a professional-grade Linter & Bridge, we prioritize stability in three key areas:

1. The Blender Bridge (Foundation)

LinkForge must remain compatible with the latest Blender LTS (Long Term Support) and the current stable release.

  • Vigilance: When a new Blender version (e.g., 6.0) enters Beta, we prioritize testing our Blender integration to ensure no API breaking changes affect our users.

2. URDF/XACRO Fidelity (Core)

Our primary goal is 100% compliance with official specifications.

  • Cross-Simulator Support: We ensure that generated files work seamlessly across Gazebo (Classic & Sim), Webots, Isaac Sim, and MuJoCo.

  • Precision: Physics calculations (inertia tensors) must remain scientifically accurate, as they are the “brain” of the exported robot.

3. The ROS 2 Ecosystem (Integration)

While LinkForge supports ros2_control, it is designed to be distribution-agnostic where possible.

  • Compatibility: We target compatibility with active ROS 2 LTS distributions (like Humble and Jazzy) and Rolling.

  • Maintenance: If the official ros2_control XML syntax changes in a newer ROS version, we update our generators to support those changes while maintaining backward compatibility.

4. Validation Extensibility (Quality Control)

To maintain the highest standards of robot description quality, LinkForge uses a Modular Validation Registry.

  • The Rule: Every new core model feature must be accompanied by a corresponding ValidationCheck in core/src/linkforge/core/validation/checks.py.

  • Implementation: Inherit from ValidationCheck, implement the run() method, and append your class to RobotValidator.DEFAULT_CHECKS.

  • Testing: Add isolated unit tests for your new check in tests/unit/core/test_validation_checks.py.

Maintainer Expectations

As a maintainer-driven project, we aim to be transparent about our availability and response times:

  • Review Cycle: Expect an initial response or feedback on PRs within 7 business days.

  • Issue Triage: New issues are usually triaged during our weekly maintenance window (typically weekends).

  • Issue Assignment & Progress:

    • If you are interested in an issue, please comment to ask for assignment.

    • We value momentum. If an assigned issue has no activity (comments or PR) for 14 days, we will check in.

    • After 21 days of inactivity, the issue may be unassigned to allow other contributors to help.

  • Public Communication: We prefer all discussions to happen in public issues or GitHub Discussions to ensure the community benefits from the shared knowledge.

  • Decision Making: For major architectural changes, we follow a consensus-based approach among core maintainers. If you are proposing a large change, please open a Discussion first to get early feedback.

Governance

LinkForge is currently maintained by @arounamounchili and the community.

  • Core Maintainers: Responsible for architectural oversight and final merging.

  • Contributors: Anyone who submits code, documentation, or feedback.

  • Recognition: We follow the All Contributors specification to recognize all types of contributions.

Getting Help

Recognition

We value every contribution! To keep things simple for maintainers, contributor recognition is fully automated:

  • README.md: Handled by the @all-contributors bot.

  • CHANGELOG.md & Release Notes: Automated via release-please based on commit messages.

  • GitHub Contributors: Managed automatically by GitHub’s platform.

All Contributors Bot

We use the @all-contributors bot to automatically recognize all types of contributions.

How to get recognized: If you’ve contributed (code, docs, ideas, etc.), you can ask the bot to add you by commenting on an issue or pull request:

@all-contributors please add @username for <contribution-type>

Replace <contribution-type> with one of the valid contribution types (e.g., code, doc, bug, etc.).

Academic Recognition

For profound core contributions (e.g., advanced mathematical noise models, novel simulator integrations, or deep physics engine refinements), we may invite you to be listed as a co-author in the CITATION.cff file and the official documentation. This ensures your high-level domain expertise is properly attributed in future academic research using LinkForge.

(Note: Standard features, basic sensor additions, and bug fixes are highly valued and will be celebrated via our standard Open Source contributors framework, but they do not automatically qualify for academic co-authorship).

Thank you for contributing to LinkForge!