diff --git a/.github/workflows/update-contributors.yml b/.github/workflows/update-contributors.yml
new file mode 100644
index 00000000000..a83a8048072
--- /dev/null
+++ b/.github/workflows/update-contributors.yml
@@ -0,0 +1,48 @@
+name: Update Contributors
+
+on:
+ push:
+ branches:
+ - main
+ workflow_dispatch: # Allows manual triggering
+
+jobs:
+ update-contributors:
+ runs-on: ubuntu-latest
+ permissions:
+ contents: write # Needed for pushing changes
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v3
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v3
+ with:
+ node-version: '18'
+ cache: 'npm'
+
+ - name: Install dependencies
+ run: npm ci
+
+ - name: Update contributors
+ run: npm run update-contributors
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Check for changes
+ id: check-changes
+ run: |
+ if [[ -n "$(git status --porcelain README.md)" ]]; then
+ echo "changes=true" >> $GITHUB_OUTPUT
+ else
+ echo "No changes to README.md"
+ fi
+
+ - name: Commit and push changes
+ if: steps.check-changes.outputs.changes == 'true'
+ run: |
+ git config --global user.name 'github-actions[bot]'
+ git config --global user.email 'github-actions[bot]@users.noreply.github.com'
+ git add README.md
+ git commit -m "docs: update contributors list [skip ci]"
+ git push
\ No newline at end of file
diff --git a/README.md b/README.md
index f907ea480ee..0dc8c068987 100644
--- a/README.md
+++ b/README.md
@@ -170,6 +170,30 @@ We love community contributions! Here’s how to get involved:
---
+
+
+## Contributors
+
+Thanks to all our contributors who have helped make Roo Code better!
+
+| 
mrubens | 
saoudrizwan | 
cte | 
samhvw8 | 
daniel-lxs | 
a8trejo |
+| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
+| 
ColemanRoo | 
stea9499 | 
joemanley201 | 
System233 | 
jquanton | 
nissa-seru |
+| 
hannesrudolph | 
MuriloFP | 
NyxJae | 
punkpeye | 
d-oit | 
monotykamary |
+| 
lloydchang | 
vigneshsubbiah16 | 
Szpadel | 
lupuletic | 
cannuri | 
Smartsheet-JB-Brown |
+| 
Premshay | 
psv2522 | 
olweraltuve | 
RaySinner | 
qdaxb | 
afshawnlotfi |
+| 
emshvac | 
Lunchb0ne | 
sammcj | 
dtrugman | 
aitoroses | 
yt3trees |
+| 
yongjer | 
vincentsong | 
pugazhendhi-m | 
eonghk | 
philfung | 
pdecat |
+| 
napter | 
mdp | 
jcbdev | 
anton-otee | 
AMHesch | 
bannzai |
+| 
dairui1 | 
dqroid | 
kinandan | 
kohii | 
lightrabbit | 
olup |
+| 
moqimoqidea | 
mosleyit | 
oprstchn | 
philipnext | 
refactorthis | 
samir-nimbly |
+| 
shaybc | 
shohei-ihaya | 
student20880 | 
PretzelVector | 
adamwlarson | 
alarno |
+| 
andreastempsch | 
Atlogit | 
dleen | 
dbasclpy | 
celestial-vault | 
DeXtroTip |
+| 
hesara | 
eltociear | 
libertyteeth | 
mamertofabian | 
marvijo-code | 
Sarke |
+| 
tgfjt | 
vladstudio | 
ashktn | | | |
+
+
+
## License
[Apache 2.0 © 2025 Roo Veterinary, Inc.](./LICENSE)
diff --git a/package.json b/package.json
index 3cfe3dee28a..bf397d5351b 100644
--- a/package.json
+++ b/package.json
@@ -307,7 +307,8 @@
"watch:tsc": "tsc --noEmit --watch --project tsconfig.json",
"watch-tests": "tsc -p . -w --outDir out",
"changeset": "changeset",
- "knip": "knip --include files"
+ "knip": "knip --include files",
+ "update-contributors": "node scripts/update-contributors.js"
},
"dependencies": {
"@anthropic-ai/bedrock-sdk": "^0.10.2",
diff --git a/scripts/update-contributors.js b/scripts/update-contributors.js
new file mode 100755
index 00000000000..cc211410006
--- /dev/null
+++ b/scripts/update-contributors.js
@@ -0,0 +1,208 @@
+#!/usr/bin/env node
+
+/**
+ * This script fetches contributor data from GitHub and updates the README.md file
+ * with a contributors section showing avatars and usernames.
+ */
+
+const https = require("https")
+const fs = require("fs")
+const path = require("path")
+
+// GitHub API URL for fetching contributors
+const GITHUB_API_URL = "https://api.github.com/repos/RooVetGit/Roo-Code/contributors?per_page=100"
+const README_PATH = path.join(__dirname, "..", "README.md")
+
+// Sentinel markers for contributors section
+const START_MARKER = ""
+const END_MARKER = ""
+
+// HTTP options for GitHub API request
+const options = {
+ headers: {
+ "User-Agent": "Roo-Code-Contributors-Script",
+ },
+}
+
+// Add GitHub token for authentication if available
+if (process.env.GITHUB_TOKEN) {
+ options.headers.Authorization = `token ${process.env.GITHUB_TOKEN}`
+ console.log("Using GitHub token from environment variable")
+}
+
+/**
+ * Fetches contributors data from GitHub API
+ * @returns {Promise} Array of contributor objects
+ */
+function fetchContributors() {
+ return new Promise((resolve, reject) => {
+ https
+ .get(GITHUB_API_URL, options, (res) => {
+ if (res.statusCode !== 200) {
+ reject(new Error(`GitHub API request failed with status code: ${res.statusCode}`))
+ return
+ }
+
+ let data = ""
+ res.on("data", (chunk) => {
+ data += chunk
+ })
+
+ res.on("end", () => {
+ try {
+ const contributors = JSON.parse(data)
+ resolve(contributors)
+ } catch (error) {
+ reject(new Error(`Failed to parse GitHub API response: ${error.message}`))
+ }
+ })
+ })
+ .on("error", (error) => {
+ reject(new Error(`GitHub API request failed: ${error.message}`))
+ })
+ })
+}
+
+/**
+ * Reads the README.md file
+ * @returns {Promise} README content
+ */
+function readReadme() {
+ return new Promise((resolve, reject) => {
+ fs.readFile(README_PATH, "utf8", (err, data) => {
+ if (err) {
+ reject(new Error(`Failed to read README.md: ${err.message}`))
+ return
+ }
+ resolve(data)
+ })
+ })
+}
+
+/**
+ * Creates HTML for the contributors section
+ * @param {Array} contributors Array of contributor objects from GitHub API
+ * @returns {string} HTML for contributors section
+ */
+function formatContributorsSection(contributors) {
+ // Filter out GitHub Actions bot
+ const filteredContributors = contributors.filter((c) => !c.login.includes("[bot]") && !c.login.includes("R00-B0T"))
+
+ // Start building with Markdown table format
+ let markdown = `${START_MARKER}
+## Contributors
+
+Thanks to all our contributors who have helped make Roo Code better!
+
+`
+ // Number of columns in the table
+ const COLUMNS = 6
+
+ // Create contributor cell HTML
+ const createCell = (contributor) => {
+ return `
${contributor.login}`
+ }
+
+ if (filteredContributors.length > 0) {
+ // Table header is the first row of contributors
+ const headerCells = filteredContributors.slice(0, COLUMNS).map(createCell)
+
+ // Fill any empty cells in header row
+ while (headerCells.length < COLUMNS) {
+ headerCells.push(" ")
+ }
+
+ // Add header row
+ markdown += `|${headerCells.join("|")}|\n`
+
+ // Add alignment row
+ markdown += "|"
+ for (let i = 0; i < COLUMNS; i++) {
+ markdown += ":---:|"
+ }
+ markdown += "\n"
+
+ // Add remaining contributor rows starting with the second batch
+ for (let i = COLUMNS; i < filteredContributors.length; i += COLUMNS) {
+ const rowContributors = filteredContributors.slice(i, i + COLUMNS)
+
+ // Create cells for each contributor in this row
+ const cells = rowContributors.map(createCell)
+
+ // Fill any empty cells to maintain table structure
+ while (cells.length < COLUMNS) {
+ cells.push(" ")
+ }
+
+ // Add row to the table
+ markdown += `|${cells.join("|")}|\n`
+ }
+ }
+
+ markdown += `${END_MARKER}`
+ return markdown
+}
+
+/**
+ * Updates the README.md file with contributors section
+ * @param {string} readmeContent Original README content
+ * @param {string} contributorsSection HTML for contributors section
+ * @returns {Promise}
+ */
+function updateReadme(readmeContent, contributorsSection) {
+ // Find existing contributors section markers
+ const startPos = readmeContent.indexOf(START_MARKER)
+ const endPos = readmeContent.indexOf(END_MARKER)
+
+ if (startPos === -1 || endPos === -1) {
+ console.warn("Warning: Could not find contributors section markers in README.md")
+ console.warn("Skipping update - please add markers to enable automatic updates.")
+ return
+ }
+
+ // Replace existing section, trimming whitespace at section boundaries
+ const beforeSection = readmeContent.substring(0, startPos).trimEnd()
+ const afterSection = readmeContent.substring(endPos + END_MARKER.length).trimStart()
+ // Ensure single newline separators between sections
+ const updatedContent = beforeSection + "\n\n" + contributorsSection.trim() + "\n\n" + afterSection
+
+ return writeReadme(updatedContent)
+}
+
+/**
+ * Writes updated content to README.md
+ * @param {string} content Updated README content
+ * @returns {Promise}
+ */
+function writeReadme(content) {
+ return new Promise((resolve, reject) => {
+ fs.writeFile(README_PATH, content, "utf8", (err) => {
+ if (err) {
+ reject(new Error(`Failed to write updated README.md: ${err.message}`))
+ return
+ }
+ resolve()
+ })
+ })
+}
+
+/**
+ * Main function that orchestrates the update process
+ */
+async function main() {
+ try {
+ const contributors = await fetchContributors()
+
+ const readmeContent = await readReadme()
+
+ const contributorsSection = formatContributorsSection(contributors)
+
+ await updateReadme(readmeContent, contributorsSection)
+ } catch (error) {
+ console.error(`Error: ${error.message}`)
+ process.exit(1)
+ }
+}
+
+// Run the script
+main()