Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
@eclipse-threadx/iot-threadx-project-leads @eclipse-threadx/iot-threadx-committers

# Decision records can be approved by any project lead or committer.
# A committer who participated in the vote can confirm the record
# faithfully reflects the outcome.
decisions/ @eclipse-threadx/iot-threadx-project-leads @eclipse-threadx/iot-threadx-committers
48 changes: 48 additions & 0 deletions .github/DISCUSSION_TEMPLATE/proposal.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
title: "[Proposal] "
labels: ["proposal"]
body:
- type: markdown
attributes:
value: |
> **Who can open proposals?** Only members of `@eclipse-threadx/iot-threadx-committers`
> or `@eclipse-threadx/iot-threadx-project-leads`.
>
> Voting opens immediately and closes **14 days** from the date this discussion is opened.

- type: textarea
id: proposal
attributes:
label: Proposal
description: What are you proposing? Be specific and self-contained.
placeholder: "I propose that we..."
validations:
required: true

- type: textarea
id: motivation
attributes:
label: Motivation
description: Why is this change needed? What problem does it solve?
validations:
required: true

- type: textarea
id: alternatives
attributes:
label: Alternatives considered
description: What other approaches were considered and why were they rejected?
validations:
required: false

- type: markdown
attributes:
value: |
---
### How to vote
Eligible voters (committers and project leads) cast their vote by posting a comment
containing exactly one of:
- `vote: yes`
- `vote: no`
- `vote: abstain`

Your last such comment is your final vote. Votes are tallied after the 14-day window closes.
19 changes: 19 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE/decision_record.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Decision Record PR

<!--
Use this template when adding a decision record to decisions/.
The validate-decisions CI check must pass before this PR can be merged.
-->

## Checklist

- [ ] File is named `DR-NNN-short-title.md`
- [ ] All required metadata fields are filled in (Status, Opened, Closed, Discussion)
- [ ] Discussion link points to the correct GitHub Discussion
- [ ] Vote tally is complete with one row per voter
- [ ] `**Result:**` line is present in the Vote Tally section
- [ ] The linked Discussion has been locked (no further voting)

## Linked Discussion

<!-- Paste the URL of the GitHub Discussion where voting took place -->
131 changes: 131 additions & 0 deletions .github/scripts/validate_decision.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
#!/usr/bin/env python3
# ***************************************************************************
# * Copyright (C) 2026 Eclipse ThreadX contributors
# *
# * This program and the accompanying materials are made available under the
# * terms of the MIT License which is available at
# * https://opensource.org/licenses/MIT.
# *
# * AI Disclosure: This file was largely AI-generated by Copilot (Sonnet 4.6).
# * The AI-generated portions may be considered public domain (CC0-1.0)
# * and not subject to the project's licence. The human contributor has
# * reviewed and verified that the code is correct.
# *
# * SPDX-License-Identifier: MIT and CC0-1.0
# ***************************************************************************
"""
Validates that decision record files conform to the required template.
Usage: python validate_decision.py decisions/DR-001-example.md [...]
Exits non-zero if any file fails validation.
"""

import re
import sys
from pathlib import Path

FILENAME_RE = re.compile(r"^DR-\d{3,}-[\w-]+\.md$")
VALID_STATUSES = {"Accepted", "Rejected", "Deferred"}

REQUIRED_TABLE_FIELDS = ["Status", "Opened", "Closed", "Discussion"]
REQUIRED_SECTIONS = ["## Proposal", "## Vote Tally"]

VOTE_ROW_RE = re.compile(r"^\|\s*@\w+\s*\|\s*(yes|no|abstain)\s*\|", re.IGNORECASE | re.MULTILINE)
RESULT_RE = re.compile(r"\*\*Result:\*\*", re.IGNORECASE)
STATUS_RE = re.compile(r"\|\s*Status\s*\|\s*(\w+)\s*\|")
DISCUSSION_RE = re.compile(r"\|\s*Discussion\s*\|\s*(https://github\.com/[^\s|]+)\s*\|")
DATE_RE = re.compile(r"\|\s*(Opened|Closed)\s*\|\s*(\d{4}-\d{2}-\d{2})\s*\|")


def validate(path: Path) -> list[str]:
errors = []

# 1. File name convention
if not FILENAME_RE.match(path.name):
errors.append(
f"Filename '{path.name}' must match DR-NNN-short-title.md "
"(e.g. DR-001-add-ci-pipeline.md)"
)

text = path.read_text(encoding="utf-8")

# 2. Required table fields
for field in REQUIRED_TABLE_FIELDS:
if not re.search(rf"\|\s*{field}\s*\|", text):
errors.append(f"Missing required metadata field: '{field}'")

# 3. Valid status value
status_match = STATUS_RE.search(text)
if status_match:
status = status_match.group(1)
if status not in VALID_STATUSES:
errors.append(
f"Invalid Status '{status}'. Must be one of: {', '.join(sorted(VALID_STATUSES))}"
)
# (missing Status field already caught above)

# 4. Discussion link is a real GitHub URL
disc_match = DISCUSSION_RE.search(text)
if not disc_match:
errors.append(
"Discussion field must contain a full GitHub URL "
"(e.g. https://github.com/eclipse-threadx/discussions/discussions/42)"
)

# 5. Opened and Closed dates are present and valid
dates_found = {m.group(1) for m in DATE_RE.finditer(text)}
for field in ("Opened", "Closed"):
if field not in dates_found:
errors.append(f"'{field}' date is missing or not in YYYY-MM-DD format")

# 6. Required sections
for section in REQUIRED_SECTIONS:
if section not in text:
errors.append(f"Missing required section: '{section}'")

# 7. Vote tally has at least one data row
if "## Vote Tally" in text:
tally_block = text.split("## Vote Tally", 1)[1].split("##")[0]
if not VOTE_ROW_RE.search(tally_block):
errors.append(
"## Vote Tally must contain at least one vote row "
"in the format '| @username | yes/no/abstain |'"
)

# 8. Result line is present
if not RESULT_RE.search(tally_block):
errors.append(
"## Vote Tally must contain a result line starting with '**Result:**'"
)

return errors


def main():
if len(sys.argv) < 2:
print("Usage: validate_decision.py <file> [file ...]")
sys.exit(1)

files = [Path(p) for p in sys.argv[1:]]
all_passed = True

for path in files:
if not path.exists():
print(f"ERROR: File not found: {path}")
all_passed = False
continue

errors = validate(path)
if errors:
all_passed = False
print(f"\n❌ {path}")
for e in errors:
print(f" • {e}")
else:
print(f"✅ {path}")

if not all_passed:
sys.exit(1)


if __name__ == "__main__":
main()
40 changes: 40 additions & 0 deletions .github/workflows/validate-decisions.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Validate Decision Records

on:
pull_request:
paths:
- "decisions/**.md"

permissions:
contents: read
pull-requests: write

jobs:
validate:
name: Validate decision record format
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Find changed decision records
id: changed
run: |
files=$(git diff --name-only origin/${{ github.base_ref }}...HEAD -- 'decisions/*.md' | tr '\n' ' ')
echo "files=$files" >> $GITHUB_OUTPUT

- name: Validate records
if: steps.changed.outputs.files != ''
run: python .github/scripts/validate_decision.py ${{ steps.changed.outputs.files }}

- name: Post validation failure comment
if: failure()
uses: actions/github-script@v7
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: "❌ **Decision record validation failed.**\n\nPlease check the workflow logs and ensure your `decisions/*.md` file follows the required template. See `VOTING.md` for the template."
})
92 changes: 92 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# Contributing to Eclipse ThreadX

Thanks for your interest in this project.

## About this repository
This repository is used to host community discussions. It also contains decision records by the project's core team.

Non-team members cannot propose pull requests on this repository. However, everyone is welcome to participate in discussions and comment on decisions considered by the core team.

The rest of this document applies to the project as a whole. Code and documentation contributions are welcome on most of our other repositories.

## Project description

Eclipse ThreadX provides a vendor-neutral, open source, safety-certified OS for
real-time applications published on under a permissive license. The Eclipse
ThreadX suite encompasses:
* ThreadX - advanced real-time operating system (RTOS) designed specifically for deeply embedded applications
* NetX Duo - advanced, industrial-grade TCP/IP network stack designed specifically for deeply embedded real-time and IoT applications
* FileX - high-performance, FAT-compatible file system that’s fully integrated with ThreadX kernel
* GUIX - provides a complete, embedded graphical user interface (GUI) library
* USBX - high-performance USB host, device, and on-the-go (OTG) embedded stack, that is fully integrated with ThreadX kernel
* LevelX - flash wear leveling for FileX and stand-alone purposes
* GuiX Studio - design environment, facilitating the creation and maintenance of all graphical elements for GUIX
* TraceX - analysis tool that provides a graphical view of real-time system events to better understand the behavior of real-time systems

Project websites:
* https://threadx.io
* https://projects.eclipse.org/projects/iot.threadx

## Terms of Use

This repository is subject to the Terms of Use of the Eclipse Foundation
https://www.eclipse.org/legal/termsofuse.php

## Developer resources

Information regarding source code management, builds, coding standards, and more.
https://projects.eclipse.org/projects/iot.threadx/developer

The project maintains the following source code repositories

* https://github.com/eclipse-threadx/.github
* https://github.com/eclipse-threadx/cmsis-packs
* https://github.com/eclipse-threadx/filex
* https://github.com/eclipse-threadx/guix
* https://github.com/eclipse-threadx/levelx
* https://github.com/eclipse-threadx/netxduo
* https://github.com/eclipse-threadx/rtos-docs-asciidoc
* https://github.com/eclipse-threadx/rtos-docs-html
* https://github.com/eclipse-threadx/samplex
* https://github.com/eclipse-threadx/threadx
* https://github.com/eclipse-threadx/tracex
* https://github.com/eclipse-threadx/usbx

## Eclipse Development Process

This Eclipse Foundation open project is governed by the Eclipse Foundation
Development Process and operates under the terms of the Eclipse IP Policy.

* https://eclipse.org/projects/dev_process
* https://www.eclipse.org/org/documents/Eclipse_IP_Policy.pdf

## Eclipse Contributor Agreement

In order to be able to contribute to Eclipse Foundation projects you must electronically sign the Eclipse Contributor Agreement (ECA).
https://www.eclipse.org/legal/ECA.php

The ECA provides the Eclipse Foundation with a permanent record that you agree
that each of your contributions will comply with the commitments documented in
the Developer Certificate of Origin (DCO). Having an ECA on file associated with
the email address matching the "Author" field of your contribution's Git commits
fulfills the DCO's requirement that you sign-off on your contributions.

For more information, please see the Eclipse Committer Handbook:
https://www.eclipse.org/projects/handbook/#resources-commit

## Contact

The project owns several mailing lists.

### Main ThreadX mailing list
News and updates about the ThreadX project and the ThreadX Alliance.
https://accounts.eclipse.org/mailing-list/threadx

### Developer mailing list
Project team conversations. Feel free to jump in and ask non-technical questions there.
https://accounts.eclipse.org/mailing-list/threadx-dev

### User mailing list
Ask your technical questions and discuss issues here.
https://accounts.eclipse.org/mailing-list/threadx-users

21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2026 Eclipse ThreadX Contributors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
23 changes: 21 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,21 @@
# discussions
Community discussion forum for Q&amp;A, feedback, and announcements. Decisions by the project team are also documented here.
# Discussions

Community discussion forum for Q&A, feedback, and announcements. Formal decisions by the project team are documented here as immutable decision records.

**Everyone is welcome to participate in discussions and comment on proposals.** Only elected [committers](https://projects.eclipse.org/projects/iot.threadx/who) may vote on formal decisions. See [VOTING.md](VOTING.md) for the full rules.

## Becoming a committer

Interested in having a vote? Start by contributing! Submit pull requests to any Eclipse ThreadX repository. Once you have built a public record of merged contributions over time, you become eligible to be nominated and elected as a committer by the existing committer team. See the [Eclipse Foundation Project Handbook — Committer Elections](https://www.eclipse.org/projects/handbook/#elections-committer) for the full process.

## Current committers

The current list of committers is published on the [Eclipse ThreadX project page](https://projects.eclipse.org/projects/iot.threadx/who).

## Key documents

| Document | Purpose |
|---|---|
| [VOTING.md](VOTING.md) | Voting rules and decision-making process |
| [decisions/TEMPLATE.md](decisions/TEMPLATE.md) | Template for authoring a decision record |
| [SSH-SIGNING.md](SSH-SIGNING.md) | How to set up SSH commit signing (required for merging decision records) |
Loading
Loading