The Open Source Project That Almost Died — Until We Hired a Vietnamese Team and Fixed Our GitHub Workflow
I’ll be honest. Our open source project was circling the drain.
We had 4,200 stars on GitHub. Decent traction. But the contribution graph told a different story. PRs sat unmerged for 18 days on average. Issues piled up faster than we could triage them. Core contributors were burning out, and new ones never stuck around.
Outsourcing Software Development in 2025: The Playbook That Actually Works
TL;DR: Outsourcing software development can cut costs by 40% and speed delivery by 2x—but only if you avoid… ...
The code wasn’t the problem. The workflow was.
Here’s the thing nobody tells you about open source: maintenance is a distributed systems problem. You’re coordinating async work across timezones, skill levels, and motivations. If your GitHub workflow isn’t bulletproof, it doesn’t matter how good your code is.
Ditch Copilot? Top Open Source AI Code Assistants That Actually Work
TL;DR: GitHub Copilot is great, but it’s not the only option. This post covers 5 open source alternatives—Continue,… ...
So we made a bet. We hired a team of three senior developers in Can Tho, Vietnam through ECOA AI, and gave them one mandate: fix our contribution pipeline.
What they built over eight weeks completely changed how we operate. Here’s the exact architecture.
The Three Killers of Open Source Projects
Before we fixed anything, we measured everything. The data was brutal:
| Metric | Before Fix | After Fix |
|---|---|---|
| Avg PR merge time | 18.3 days | 2.1 days |
| Issue triage lag | 9.7 days | 4.2 hours |
| First-time contributor retention | 12% | 47% |
| CI failure rate on main | 23% | 3% |
Three patterns were killing us. Let’s break each one down.
1. PRs Were a Black Hole
Contributors would open a PR. Then silence. No review. No feedback. No merge.
Why? Because our core team was drowning. We had no standardized PR template, no automated checks beyond basic linting, and no SLA for review turnaround. Contributors felt ignored, so they left.
2. Issues Were a Dumping Ground
Anyone could open an issue. And they did. Feature requests, bug reports, configuration questions, “how do I install this?” — all mixed together. No labels. No triage. No owner.
We were treating every issue equally, which meant nothing got prioritized.
3. CI Was Unreliable
Our CI pipeline broke constantly. Tests would pass locally but fail on GitHub Actions because of environment drift. We had no caching strategy, no matrix builds for different Python versions, and no artifact retention for debugging.
The failure rate hit 23% at one point. Developers stopped trusting the green checkmark.
What the Vietnamese Team Built (Exact Architecture)
The team in Can Tho didn’t just “improve things.” They rebuilt our entire GitHub workflow from the ground up. Here’s what they shipped.
The PR Template That Actually Works
Most PR templates are useless. They ask for a description and a checklist that nobody reads.
Our team designed a template that forces contributors to provide exactly what reviewers need:
markdown
## Summary
## Related Issue
## Type of Change
- [ ] Bug fix (non-breaking)
- [ ] New feature (non-breaking)
- [ ] Breaking change
- [ ] Documentation update
## Testing
- [ ] Unit tests added/updated
- [ ] Integration tests pass
- [ ] Manual testing performed
## Screenshots
## Checklist
- [ ] My code follows the project's style guidelines
- [ ] I have performed a self-review
- [ ] I have commented complex logic
- [ ] My changes generate no new warnings
- [ ] I have updated the documentation
Simple, right? But the impact was immediate. PRs with this template got 3x faster reviews because reviewers didn’t have to chase down context.
The Issue Triage Bot That Cut Lag by 97%
We built a custom GitHub Action that automatically triages new issues. It runs on `issues.opened` and does three things:
- Classifies the issue type using label patterns and keyword matching
- Assigns a priority based on issue templates
- Assigns a primary maintainer based on a round-robin rotation
Here’s the core logic:
yaml
name: Issue Triage
on:
issues:
types: [opened]
jobs:
triage:
runs-on: ubuntu-latest
steps:
- uses: actions/github-script@v7
with:
script: |
const issue = context.payload.issue;
const title = issue.title.toLowerCase();
const body = issue.body || '';
// Classification
let labels = ['needs-triage'];
if (body.includes('bug') || body.includes('error') || body.includes('crash')) {
labels.push('bug');
}
if (title.includes('feature') || title.includes('request') || body.includes('feature')) {
labels.push('enhancement');
}
if (body.includes('how do i') || body.includes('question') || title.includes('help')) {
labels.push('question');
}
// Priority assignment
if (labels.includes('bug') && (body.includes('production') || body.includes('critical'))) {
labels.push('priority-high');
}
// Assign labels
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
labels: labels
});
// Round-robin assignment
const maintainers = ['dev1', 'dev2', 'dev3'];
const assignee = maintainers[issue.number % maintainers.length];
await github.rest.issues.addAssignees({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
assignees: [assignee]
});
This bot alone cut our issue triage lag from 9.7 days to 4.2 hours. Not because it’s smart — because it’s consistent. Every issue gets the same treatment, every time.
Standardized CI/CD That Actually Stays Green
The Vietnamese team rebuilt our CI pipeline from scratch. They focused on three things:
- Caching: Docker layer caching + pip cache + pre-commit cache
- Matrix builds: Python 3.10, 3.11, 3.12 on Ubuntu, macOS, Windows
- Fail-fast with reporting: If a job fails, it posts the error directly to the PR
Here’s the reusable workflow they created:
yaml
name: CI
on:
pull_request:
branches: [main]
push:
branches: [main]
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
python-version: ['3.10', '3.11', '3.12']
fail-fast: false
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'
- uses: actions/cache@v4
with:
path: ~/.cache/pre-commit
key: pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
- run: pip install -r requirements-dev.txt
- run: pre-commit run --all-files
- run: pytest --cov=./ --cov-report=xml
- name: Post failure comment
if: failure() && github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: `❌ CI failed on ${{ matrix.os }} with Python ${{ matrix.python-version }}. Check the [logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}).`
});
The `fail-fast: false` line is critical. If one matrix build fails, the others keep running. You get the full picture of what’s broken, not just the first failure.
CI failure rate dropped from 23% to 3%. Developers started trusting the pipeline again.
Why a Vietnamese Team Made the Difference
You might be thinking: “Couldn’t any competent team have done this?”
Sure. But here’s what made the Can Tho team special.
They weren’t just executing tickets. They owned the problem. The senior developer we hired spent his first week reading every open issue, every stale PR, and every CI log. He didn’t just ask “what should I build?” — he asked “what’s actually breaking here?”
That’s the difference between a contractor and a partner. And it’s why we’re now expanding to three more developers through ECOA AI.
Honestly, the cost was a factor too. At $3,000/month for a senior developer in Vietnam, we got world-class talent for a fraction of US rates. But the real ROI wasn’t the cost savings. It was the speed of iteration.
Our Vietnamese team could ship a GitHub Action, test it across 12 OS/Python combinations, and deploy it in the same day. Try doing that with a local hire at $150/hour.
The Metrics That Matter Now
Six months after the workflow overhaul, here’s where we stand:
- PR merge time: 2.1 days (down from 18.3)
- Issue triage lag: 4.2 hours (down from 9.7 days)
- First-time contributor retention: 47% (up from 12%)
- CI failure rate: 3% (down from 23%)
- Monthly active contributors: 28 (up from 6)
The project didn’t just survive. It’s thriving.
Frequently Asked Questions
How do I convince my open source co-maintainers to adopt a standardized PR template?
Start with data. Show them your current PR merge times and contributor drop-off rates. Most maintainers don’t realize how bad the problem is until you measure it. Then propose a 30-day trial with the template. Track the metrics. When they see PRs getting merged 3x faster, they’ll never go back.
What’s the best way to handle issue triage automation without over-engineering it?
Don’t build a custom bot with ML classification. That’s overkill. Start with a simple GitHub Action that applies labels based on keyword matching in the issue title and body. Use issue templates with checkboxes to force contributors to self-classify. The goal isn’t perfect classification — it’s getting every issue assigned to a human within 4 hours.
How do I ensure CI consistency across different operating systems?
Use matrix builds with `fail-fast: false` so you see all failures, not just the first one. Cache aggressively — Docker layers, pip packages, pre-commit hooks. And most importantly, run your CI on the same OS configurations your users actually use. If your library supports Windows, test on Windows. Don’t assume Linux coverage is enough.
Can a distributed team really maintain an open source project effectively?
Yes, but only if you invest in async communication. We use GitHub Discussions for design decisions, not Slack. Every decision is documented in an issue or PR. Our Vietnamese team works Vietnam business hours, which overlaps with European afternoon and US morning. The key is writing everything down and never relying on real-time communication for critical decisions.
Related reading: Vietnam Outsourcing: The Smartest Move for Your Offshore Development in 2025
Related reading: Why Outsourcing Software Development to Vietnam Beats India and the Philippines in 2025