Skip to content
Dev Tools Beginner Tutorial

Open Source Your Side Project the Right Way

Turn a personal repo into a contributor-ready GitHub project with a license, README badge, templates, and CI.

Lenn Voss
Lenn Voss
Cloud & Infrastructure Writer · Aug 25, 2026 · 6 min read
Open Source Your Side Project the Right Way

What you'll build / learn

You'll take an existing local git repo and turn it into a public, contributor-ready GitHub project: an MIT license, a README with a live CI badge, a CONTRIBUTING guide, a structured bug-report issue form, a pull request template, and a GitHub Actions workflow that runs your tests on every push and PR — all from the terminal.

Prerequisites

Verified on macOS 26 with:

  • git 2.50 — any 2.x works.
  • GitHub CLI (gh) 2.86, authenticated: run gh auth login once if gh auth status doesn't show "Logged in".
  • A GitHub account and a local project with at least one commit. The CI step assumes a Node project with an npm test script; swap that one line for your stack (pytest, go test ./..., etc.).
  • Action versions verified: actions/checkout@v7, actions/setup-node@v7.

Commands are POSIX shell; on Windows use Git Bash or WSL.

1. Pick a license and add it

No license means nobody can legally use or contribute to your code. For a side project, MIT is the safe default — it lets people do almost anything, including ship closed-source forks; pick GPLv3 if you want derivatives to stay open. Compare options at choosealicense.com, which GitHub maintains.

gh can print any of GitHub's license templates. Write it to LICENSE (that exact filename is what GitHub's license detection looks for) and fill in the placeholders:

cd ~/code/my-project   # your repo
gh repo license view mit > LICENSE
sed -i '' 's/\[year\]/2026/; s/\[fullname\]/Your Name/' LICENSE   # macOS sed; on Linux drop the ''
head -3 LICENSE

gh repo license list shows the other keys (apache-2.0, gpl-3.0, …).

2. Write a README that answers three questions

A contributor-ready README says what the project does, how to run it, and how to help. The badge line goes live after step 6 — replace OWNER/my-project with your GitHub handle and repo name here and in every later snippet:

# my-project

[![CI](https://github.com/OWNER/my-project/actions/workflows/ci.yml/badge.svg)](https://github.com/OWNER/my-project/actions/workflows/ci.yml)

One sentence on what this does and who it's for.

## Install

    npm install my-project

## Usage

    my-project --help

## Contributing

See [CONTRIBUTING.md](CONTRIBUTING.md). Bug reports and PRs welcome.

## License

MIT — see [LICENSE](LICENSE).

Save that as README.md.

3. Add a CONTRIBUTING guide

GitHub links this file whenever someone opens an issue or PR and adds a "Contributing" tab to the repo overview. It can live in the root, .github/, or docs/; root is most discoverable.

cat > CONTRIBUTING.md <<'MD'
# Contributing

Thanks for helping out. Here's the short version.

## Setup

1. Fork and clone the repo.
2. `npm install`
3. `npm test` — make sure it's green before you start.

## Making changes

- Open an issue first for anything bigger than a bug fix, so we can agree on the approach.
- Create a branch from `main`: `git switch -c fix/short-description`.
- Add or update tests for what you changed.
- Keep PRs focused: one change per PR.

## Submitting

Push your branch and open a pull request against `main`. CI must pass. I usually review within a few days.
MD

4. Add an issue form and a PR template

Issue forms are YAML files in .github/ISSUE_TEMPLATE/ that GitHub renders as structured web forms, so bug reports arrive with repro steps instead of "it doesn't work". name, description, and body are required; body needs at least one non-markdown field.

mkdir -p .github/ISSUE_TEMPLATE
cat > .github/ISSUE_TEMPLATE/bug_report.yml <<'YML'
name: Bug report
description: Something isn't working as expected.
title: "[Bug]: "
labels: ["bug"]
body:
  - type: textarea
    id: what-happened
    attributes:
      label: What happened?
      description: What did you expect to happen instead?
    validations:
      required: true
  - type: textarea
    id: repro
    attributes:
      label: Steps to reproduce
      placeholder: "1. Run ...\n2. See error ..."
    validations:
      required: true
  - type: input
    id: version
    attributes:
      label: Version
      placeholder: e.g. 1.2.0
  - type: textarea
    id: logs
    attributes:
      label: Relevant log output
      render: shell
YML

labels only applies if the label already exists — bug is one of GitHub's defaults. Now discourage blank issues and point questions elsewhere:

cat > .github/ISSUE_TEMPLATE/config.yml <<'YML'
blank_issues_enabled: false
contact_links:
  - name: Question
    url: https://github.com/OWNER/my-project/discussions
    about: Ask usage questions here instead of opening an issue.
YML

The PR template is plain Markdown at .github/pull_request_template.md (lowercase filename matters):

cat > .github/pull_request_template.md <<'MD'
## What does this PR do?

## How was it tested?

- [ ] Added/updated tests
- [ ] `npm test` passes locally
MD

5. Add a CI workflow

mkdir -p .github/workflows
cat > .github/workflows/ci.yml <<'YML'
name: CI
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - uses: actions/setup-node@v7
        with:
          node-version: 22
      - run: npm ci
      - run: npm test
YML

The workflow's name: CI is what the badge displays; the filename ci.yml is what the badge URL references.

6. Publish the repo

Commit everything, then create the GitHub repo from the local directory and push in one command (--license can't be combined with --source, which is why step 1 wrote LICENSE by hand):

git add -A
git commit -m "Add license, README, contributing guide, templates, and CI"
gh repo create my-project --public --source=. --remote=origin --push

Expected output:

✓ Created repository OWNER/my-project on github.com
  https://github.com/OWNER/my-project
✓ Added remote https://github.com/OWNER/my-project.git
✓ Pushed commits to https://github.com/OWNER/my-project.git

The push triggers the first CI run, which populates the badge.

Verify it works

Give the push a minute, then check the run from the terminal:

gh run list --workflow ci.yml --limit 1 --json workflowName,status,conclusion --jq '.[0]'

Expected output:

{"conclusion":"success","status":"completed","workflowName":"CI"}

If status is still in_progress, re-run in a few seconds. Then open the repo in a browser (gh repo view --web). Confirm:

  • The README badge reads CI passing (green).
  • The MIT license appears in the About sidebar.
  • Insights → Community Standards shows green checks for README, License, Contributing, and Issue templates.
  • Issues → New issue shows your "Bug report" form and the "Question" contact link. You'll still see Blank issue marked Maintainers only — that's expected; contributors with read access won't.

Troubleshooting

the --source option is not supported with --clone, --template, --license, or --gitignore — you passed --license alongside --source=.. Drop --license; the local LICENSE file from step 1 is all GitHub needs.

--push enabled but no commits found in /path/to/my-project — the directory is a git repo but has nothing committed. Run git add -A && git commit -m "Initial commit" and re-run gh repo create.

error: remote origin already exists. — the repo already has an origin (for example from an earlier private remote). Either git remote remove origin first, or pass a different name such as --remote=github and push with git push -u github main.

Badge is a broken image (URL returns 404) — the badge URL is built from the workflow filename, not its name:. Check it's .../actions/workflows/ci.yml/badge.svg and that the file is actually at .github/workflows/ci.yml on main. The badge only exists once GitHub has registered the workflow, i.e. after the first push.

Issue form doesn't appear, or the chooser says Body must contain at least one non-markdown field — YAML validation failed. GitHub shows the exact message (Required top level key name is missing, Body must have unique ids, …) when you open the file on github.com. Fix the key it names; id values may only contain letters, numbers, - and _.

Next steps

  • Finish the Community Standards checklist: Add file → Create new file → CODE_OF_CONDUCT.md → Choose a code of conduct template, and Security → Security policy → Start setup for SECURITY.md.
  • Protect main: Settings → Rules → Rulesets, require the test check to pass before merging.
  • Tag good starter issues with good first issue — GitHub surfaces those to newcomers.
  • Cut a first release with gh release create v0.1.0 --generate-notes so people have something versioned to depend on.

Sources & further reading

  1. gh repo create - GitHub CLI manual — cli.github.com
  2. Syntax for issue forms — docs.github.com
  3. Configuring issue templates for your repository — docs.github.com
  4. Setting guidelines for repository contributors — docs.github.com
  5. Adding a workflow status badge — docs.github.com
  6. Choose an open source license — choosealicense.com
Lenn Voss
Written by
Lenn Voss · Cloud & Infrastructure Writer

Lenn writes about cloud platforms, Kubernetes internals, and the infrastructure decisions that quietly make or break engineering organizations. Based in Berlin's vibrant tech scene, they have a talent for turning dense platform-engineering topics into prose that people actually finish reading.

Discussion 0

Join the discussion

Sign in or create an account to comment and vote.

No comments yet

Be the first to weigh in.

Related Reading