Tools: I paused feature work on day one to set up CI — and avoided the same slow chaos again

Tools: I paused feature work on day one to set up CI — and avoided the same slow chaos again

The day-one baseline I actually shipped

The first run passed — and that didn’t make it optional

The assumption I had to unlearn

What changed after installing CI first

Why this matters on small codebases too

What I’ll repeat every time now

Takeaways I was ready to ship my first real feature. Editor open. Tasks clear. Momentum high. Then I stopped, closed that branch idea, and spent the session setting up CI instead. In the moment, it felt like I was delaying progress. There were no users yet, no incidents, no red alerts. But I had seen the opposite path before: skip CI early, move fast for a week, then slowly lose speed to noisy PRs, inconsistent checks, and “works on my machine” friction. Not one big disaster. Just constant drag. So this time I treated CI as infrastructure, not polish. I kept it intentionally small: No matrix builds. No release automation. No deployment steps.

Just one non-negotiable rule: If checks fail, nothing merges. This was the exact baseline workflow I shipped on day one: That was enough to make quality objective from day one. My first run went green immediately. First CI run: both baseline checks (lint and test) passed. The point wasn’t complexity — it was installing merge guardrails from day one. Past me would have used that as evidence CI could wait: “See? Nothing broke.” First CI run: both baseline checks (lint and test) passed. The point wasn’t complexity — it was installing merge guardrails from day one. But that was the wrong lens. The value wasn’t catching a bug on day one.The value was removing ambiguity before complexity arrived. Without CI, quality becomes social: With CI, quality becomes mechanical: Fewer opinions. Less friction. Cleaner reviews. I used to think this sequence was efficient: In practice, “later” came with interest: It looked faster early and got slower every week after. The biggest cost wasn’t bugs. It was momentum decay. The technical setup was simple. The behavioral shift was massive. I wrote commits with merge gates in mind from the start. I reviewed changes with less noise.“Done” had a stable meaning. Even as a solo builder, this mattered more than I expected. CI became my second pair of eyes: consistent, fast, and impossible to forget. And because the pipeline was small, maintenance stayed cheap. CI is often framed as “team process.” I now think that’s backwards. Small projects change rapidly. Early habits harden quickly. If standards are vague in week one, that vagueness leaks into architecture decisions and review culture. A tiny pipeline early prevents that drift before it starts. You don’t need enterprise-level complexity.You need a clear baseline that no one has to debate. If I start another codebase tomorrow, I’ll follow the same order: Not because it looks sophisticated.

Because it protects momentum when the project gets real. The lesson wasn’t “CI is useful.” The lesson was timing: The best moment to install guardrails was before I felt the crash. If you want to follow the build-in-public journey: Templates let you quickly answer FAQs or store snippets for re-use. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse

Code Block

Copy

name: CI on: push: pull_request: branches: - main jobs: lint: runs-on: ubuntu-latest steps: - name: Check out repository uses: actions/checkout@v5 - name: Install uv uses: astral-sh/setup-uv@v7 - name: Set up Python uses: actions/setup-python@v6 with: python-version: "3.13" - name: Run Ruff run: uv run ruff check . test: runs-on: ubuntu-latest steps: - name: Check out repository uses: actions/checkout@v5 - name: Install uv uses: astral-sh/setup-uv@v7 - name: Set up Python uses: actions/setup-python@v6 with: python-version: "3.13" - name: Run pytest run: uv run pytest name: CI on: push: pull_request: branches: - main jobs: lint: runs-on: ubuntu-latest steps: - name: Check out repository uses: actions/checkout@v5 - name: Install uv uses: astral-sh/setup-uv@v7 - name: Set up Python uses: actions/setup-python@v6 with: python-version: "3.13" - name: Run Ruff run: uv run ruff check . test: runs-on: ubuntu-latest steps: - name: Check out repository uses: actions/checkout@v5 - name: Install uv uses: astral-sh/setup-uv@v7 - name: Set up Python uses: actions/setup-python@v6 with: python-version: "3.13" - name: Run pytest run: uv run pytest name: CI on: push: pull_request: branches: - main jobs: lint: runs-on: ubuntu-latest steps: - name: Check out repository uses: actions/checkout@v5 - name: Install uv uses: astral-sh/setup-uv@v7 - name: Set up Python uses: actions/setup-python@v6 with: python-version: "3.13" - name: Run Ruff run: uv run ruff check . test: runs-on: ubuntu-latest steps: - name: Check out repository uses: actions/checkout@v5 - name: Install uv uses: astral-sh/setup-uv@v7 - name: Set up Python uses: actions/setup-python@v6 with: python-version: "3.13" - name: Run pytest run: uv run pytest - one lint job - one test job - same Python/tooling assumptions in local and CI - “I ran tests locally.” - “It passed for me.” - “We’ll clean that up in the next PR.” - Build features first. - Formalize quality later. - Conventions drifted before they were written - Test habits became inconsistent - Cleanup PRs grew bigger than feature PRs - Review energy went to mechanics instead of architecture - Add lint + test CI - Enforce checks on merge - Then accelerate features - Day-one CI is not overengineering; it’s anti-chaos insurance. - A minimal lint+test pipeline is enough to prevent early process drift. - A green first run is still a win: it means your standards are in place before complexity compounds. - GitHub: https://github.com/OranguStudio - X: https://x.com/OranguEngineer