Skip to content

Commit 7ba7547

Browse files
Add alphabetical linter and fix all sections to be sorted
- Add scripts/check-alphabetical.py linter for CI - Add .github/workflows/alphabetical-check.yml CI on PRs touching README.md - Sort Development & Workflow section alphabetically - Sort Guides & Articles section alphabetically - Sort Related Projects section alphabetically
1 parent 6b6c049 commit 7ba7547

3 files changed

Lines changed: 116 additions & 9 deletions

File tree

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
name: Alphabetical Order Check
2+
3+
on:
4+
pull_request:
5+
paths:
6+
- "README.md"
7+
8+
jobs:
9+
alphabetical:
10+
runs-on: ubuntu-latest
11+
steps:
12+
- uses: actions/checkout@v4
13+
- uses: actions/setup-python@v5
14+
with:
15+
python-version: "3.12"
16+
- run: python3 scripts/check-alphabetical.py README.md

README.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,12 @@ Third-party plugins built by the community. [PRs welcome](#contributing)!
5555

5656
### Development & Workflow
5757

58-
- [Registry Broker](https://github.com/hashgraph-online/registry-broker-codex-plugin) - Delegate tasks to specialist AI agents via the HOL Registry, plan, find, summon, and recover sessions.
59-
- [Project Autopilot](https://github.com/AlexMi64/codex-project-autopilot) - Turn an idea into a structured project workflow with planning, execution, verification, and handoff.
60-
- [Codex Reviewer](https://github.com/schuettc/codex-reviewer) - Second-pass review of Claude-driven plans and implementations.
58+
- [AgentOps](https://github.com/boshu2/agentops) - DevOps layer for coding agents with flow, feedback, and memory that compounds between sessions.
6159
- [Codex Multi Auth](https://github.com/ndycode/codex-multi-auth) - Multi-account OAuth manager for the official Codex CLI with switching, health checks, and recovery tools.
60+
- [Codex Reviewer](https://github.com/schuettc/codex-reviewer) - Second-pass review of Claude-driven plans and implementations.
6261
- [HOTL Plugin](https://github.com/yimwoo/hotl-plugin) - Human-on-the-Loop AI coding workflow plugin for Codex, Claude Code, and Cline with structured planning, review, and verification guardrails.
63-
- [AgentOps](https://github.com/boshu2/agentops) - DevOps layer for coding agents with flow, feedback, and memory that compounds between sessions.
62+
- [Project Autopilot](https://github.com/AlexMi64/codex-project-autopilot) - Turn an idea into a structured project workflow with planning, execution, verification, and handoff.
63+
- [Registry Broker](https://github.com/hashgraph-online/registry-broker-codex-plugin) - Delegate tasks to specialist AI agents via the HOL Registry, plan, find, summon, and recover sessions.
6464

6565
### Tools & Integrations
6666

@@ -81,8 +81,8 @@ Third-party plugins built by the community. [PRs welcome](#contributing)!
8181

8282
### Getting Started
8383

84-
- [Official Docs: Build Plugins](https://developers.openai.com/codex/plugins/build) - Author and package plugins.
8584
- [Official Docs: Agent Skills](https://developers.openai.com/codex/skills) - The skill authoring format.
85+
- [Official Docs: Build Plugins](https://developers.openai.com/codex/plugins/build) - Author and package plugins.
8686
- [Plugin Structure](https://developers.openai.com/codex/plugins/build#create-a-plugin-manually) - `.codex-plugin/plugin.json` manifest format.
8787

8888
### Plugin Anatomy
@@ -115,17 +115,17 @@ Currently no self-serve marketplace submission. Plugins are distributed via loca
115115
## Guides & Articles
116116

117117
- [Codex Plugins, Visually Explained](https://adithyan.io/blog/codex-plugins-visual-explainer) - Visual walkthrough by @adithyan.
118+
- [Codex Plugins: Slack, Figma, Google Drive](https://arstechnica.com/ai/2026/03/openai-brings-plugins-to-codex-closing-some-of-the-gap-with-claude-code/) - Ars Technica feature deep dive.
118119
- [Codex v0.117.0 Plugin Walkthrough](https://reddit.com/r/codex/) - Reddit explainer.
119120
- [OpenAI's Codex Gets Plugins](https://thenewstack.io/openais-codex-gets-plugins/) - The New Stack ecosystem overview.
120-
- [Codex Plugins: Slack, Figma, Google Drive](https://arstechnica.com/ai/2026/03/openai-brings-plugins-to-codex-closing-some-of-the-gap-with-claude-code/) - Ars Technica feature deep dive.
121121

122122
## Related Projects
123123

124+
- [agentskills.io](https://agentskills.io) - Open agent skills standard.
125+
- [antigravity-awesome-skills](https://github.com/sickn33/antigravity-awesome-skills#readme) - Cross-agent skill library (Claude, Codex, Cursor, Gemini).
126+
- [awesome-claude-code](https://github.com/hesreallyhim/awesome-claude-code#readme) - Claude Code resources.
124127
- [awesome-coding-agents](https://github.com/e2b-dev/awesome-ai-agents#readme) - Curated list of AI coding agents.
125128
- [awesome-mcp-servers](https://github.com/wong2/awesome-mcp-servers#readme) - MCP server directory.
126-
- [awesome-claude-code](https://github.com/hesreallyhim/awesome-claude-code#readme) - Claude Code resources.
127-
- [antigravity-awesome-skills](https://github.com/sickn33/antigravity-awesome-skills#readme) - Cross-agent skill library (Claude, Codex, Cursor, Gemini).
128-
- [agentskills.io](https://agentskills.io) - Open agent skills standard.
129129

130130
## Contributing
131131

scripts/check-alphabetical.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
#!/usr/bin/env python3
2+
"""Linter: verify that list entries within each section of README.md are alphabetically sorted."""
3+
4+
import re
5+
import sys
6+
from pathlib import Path
7+
8+
9+
def extract_sections(filepath: str) -> list[tuple[str, str, list[str]]]:
10+
"""Extract sections and their list items from a markdown file.
11+
12+
Returns list of (section_heading, context, items) where items are the display text.
13+
"""
14+
content = Path(filepath).read_text()
15+
lines = content.split("\n")
16+
17+
sections = []
18+
current_heading = None
19+
current_items: list[tuple[str, int]] = [] # (display_text, line_number)
20+
21+
# Regex for markdown list items with links: "- [Display Text](url) - description"
22+
# Also handles plain list items: "- Display Text - description"
23+
item_re = re.compile(r"^- \[([^\]]+)\]\([^)]+\)", re.IGNORECASE)
24+
25+
for i, line in enumerate(lines, 1):
26+
# Detect section headers (## or ###)
27+
heading_match = re.match(r"^(#{2,3})\s+(.+)", line)
28+
# Also detect <summary> tags as section boundaries inside <details>
29+
summary_match = re.match(r"<summary>(.+)</summary>", line.strip())
30+
31+
if heading_match:
32+
# Save previous section if it has items
33+
if current_heading and current_items:
34+
sections.append((current_heading, [t for t, _ in current_items]))
35+
current_heading = heading_match.group(2).strip()
36+
current_items = []
37+
elif summary_match:
38+
if current_heading and current_items:
39+
sections.append((current_heading, [t for t, _ in current_items]))
40+
current_heading = f"[{summary_match.group(1).strip()}]"
41+
current_items = []
42+
elif item_re.match(line):
43+
display_text = item_re.match(line).group(1)
44+
current_items.append((display_text.lower(), i))
45+
46+
# Don't forget the last section
47+
if current_heading and current_items:
48+
sections.append((current_heading, [t for t, _ in current_items]))
49+
50+
return sections
51+
52+
53+
def check_sorted(items: list[str]) -> bool:
54+
"""Return True if items are alphabetically sorted."""
55+
return all(items[i] <= items[i + 1] for i in range(len(items) - 1))
56+
57+
58+
def main():
59+
readme = sys.argv[1] if len(sys.argv) > 1 else "README.md"
60+
61+
if not Path(readme).exists():
62+
print(f"ERROR: {readme} not found")
63+
sys.exit(1)
64+
65+
sections = extract_sections(readme)
66+
errors = 0
67+
68+
skip_sections = {"Contents"} # TOC follows document order, not alphabetical
69+
70+
for heading, items in sections:
71+
if not items or heading in skip_sections:
72+
continue
73+
if not check_sorted(items):
74+
sorted_items = sorted(items)
75+
print(f"FAIL: Section '{heading}' is not alphabetically sorted.")
76+
print(f" Current order: {', '.join(items)}")
77+
print(f" Expected order: {', '.join(sorted_items)}")
78+
errors += 1
79+
else:
80+
print(f"OK: '{heading}' ({len(items)} items)")
81+
82+
if errors:
83+
print(f"\n{errors} section(s) failed alphabetical check.")
84+
sys.exit(1)
85+
else:
86+
print("\nAll sections are alphabetically sorted.")
87+
sys.exit(0)
88+
89+
90+
if __name__ == "__main__":
91+
main()

0 commit comments

Comments
 (0)