Thanks for your contribution. Bug fixes, new widgets, improved docs, typo fixes. All of it helps.
🎯 GSSoC 2026 contributors: jump to the GSSoC section below. Read it before you open any PR.
Before you start, make sure you have:
| Requirement | Version | Notes |
|---|---|---|
| Bun | >= 1.3.0 | Install Bun — bun --version to check |
| Node.js | >= 18.0.0 | Only needed if you consume published @termuijs/* packages from npm — Install Node.js |
| Git | Latest | git --version to check |
| Terminal | — | Must support ANSI escape codes (most modern terminals do) |
git clone https://github.com/Karanjot786/TermUI.git
cd TermUI
bun install
bun run build
bun run testYou need Bun 1.3 or newer. The project is a Bun workspace monorepo with 14 packages under packages/. Node 18+ matters only if you consume published @termuijs/* packages from npm. Development is Bun-only.
For local development setup and workspace commands, see DEVELOPMENT.md.
Framework code lives here. Docs site lives in a separate repo.
| Repo | Contents | Where to send your PR |
|---|---|---|
| TermUI (this repo) | 14 packages, examples, tests, scaffolding CLI | Bug fixes, new widgets, hooks, refactors, tests |
| TermUI_Docs | termui.io source: Vite + TanStack + MDX content | Doc typos, new doc pages, website UI changes |
TermUI_Docs on GitHub. GSSoC 2026 counts only on this repo; the docs repo does not participate.
packages/
core/ Screen buffer, layout engine, input, events
widgets/ Box, Text, Table, ProgressBar, Spinner, Gauge, VirtualList
ui/ Select, Tabs, Modal, Toast, Tree, Form, CommandPalette
jsx/ TSX runtime with hooks
store/ Global state management
tss/ Terminal Style Sheets
router/ Screen routing
motion/ Spring animations
data/ System monitoring (CPU, memory, disk, processes)
testing/ In-memory test renderer
dev-server/ Hot-reload dev server (uses Bun.spawn)
quick/ Fluent builder API
create-termui-app/ Project scaffolding CLI
examples/ Working example apps
API docs for each package live on https://www.termui.io. Edit those pages in TermUI_Docs.
Welcome! If this is your first time contributing to TermUI, follow these steps in order.
TermUI uses Bun 1.3 or newer. Check yours:
bun --versionIf it is older than 1.3, update it:
curl -fsSL https://bun.sh/install | bashFork the repo on GitHub first. Then clone your fork (not the original):
git clone https://github.com/<your-username>/TermUI.git
cd TermUIbun install
bun run buildBuild order matters in a monorepo. Always run bun run build from the root — it builds all 14 packages in the correct dependency order automatically.
bun run testAll 598 tests should pass before you make any changes. If any test fails before you touch anything, open an issue and report it.
Never work on main directly. Create a branch:
git checkout -b feat/your-feature-name
# or
git checkout -b fix/your-bug-nameBranch naming format: type/short-description. Example: fix/empty-list-crash.
After your changes, always run all three checks:
bun run build && bun run test && bun run typecheckAll three must pass before you open a PR.
Bun is not installed. Install it:
curl -fsSL https://bun.sh/install | bashThen restart your terminal.
Always run bun install from the root of the repo, not inside a package folder.
This usually means a missing build step. Run:
bun run build
bun run testIf tests still fail, comment on the issue and tag @Karanjot786.
Make sure you exported your new widget from the package's index.ts. Every new export must be registered there.
Before you open your PR, go through this list:
- I starred the repo ⭐
- I claimed the issue before starting work
- My branch name follows
type/short-descriptionformat - I ran
bun run build && bun run test && bun run typecheck— all pass - I added a test for my change
- My PR title follows
type(scope): short descriptionformat - I linked the issue in my PR body with
Closes #N - I filled every section of the PR template
- Check existing issues. Someone might already work on it.
- Open an issue first for anything larger than a small fix. Describe your change and your reason. Saves everyone time if the approach needs discussion.
- One pull request per change. Do not bundle unrelated fixes.
Using Claude Code, Copilot, Cursor, or another agent is welcome. Most PRs here are written with one. The agent does better work when you set it up right.
- Point the agent at the rules. This repo has
AGENTS.mdat the root and one in each major package (packages/widgets/AGENTS.md,packages/ui/AGENTS.md, and others). Claude Code and Copilot read these automatically. Tell your agent to read the rootAGENTS.mdand the one for the package you are working in before it writes code. - Give it the whole issue. Issues opened with the AI-ready task template carry everything the agent needs: the exact files, the API signature, the acceptance criteria, the test command, and a reference file to copy. Paste the full issue to your agent. Do not summarize it.
- Run plan mode first for anything bigger than a one-line fix. In Claude Code, ask for a plan before edits. Read the plan. Confirm it touches only the files the issue names.
- You own the PR, not the agent. Read the diff before you push. Run
bun run build && bun vitest run && bun run typecheckyourself. If you do not understand a line the agent wrote, do not submit it. PRs that are clearly generated without understanding get thegssoc:ai-sloplabel and earn zero points. - Keep it surgical. Agents like to refactor nearby code, reformat files, and add features no one asked for. Reject that. One change per PR. If
bun.lockshows changes unrelated to your work, revert it withgit checkout origin/main -- bun.lock.
- TypeScript strict mode. No
anywithout an inline comment explaining why. - No external runtime dependencies in
@termuijs/core. The core stays dependency-free. - Use
node:prefix for built-in modules. Example:import { readFileSync } from 'node:fs'. - Every state-mutating method on a widget calls
this.markDirty().
Every package uses Vitest. Tests live next to source files. Example: foo.ts plus foo.test.ts.
# Run all tests
bun run test
# Run tests for a single package
bun vitest run packages/core
# Run a single test file
bun vitest run packages/widgets/src/data/Gauge.test.ts
# Watch mode
bun run test:watchAdd a test when you add a widget or fix a bug. Look at existing tests in the same package for patterns.
# Build all packages
bun run build
# Build a single package
cd packages/core && bun run buildEach package uses tsup. Output goes to dist/ with both ESM and CJS formats. Published artifacts run on Node 18+ and Bun.
- Fork the repo. Create a branch from
main. Branch name:type/short-description. Example:fix/empty-list-crash. - ⭐ Star the repo before you open your PR. The
star-checkjob fails otherwise. - Make your changes.
- Run
bun run build && bun run test && bun run typecheck. All three pass. - Write your PR title in the form
type: short description. Example:fix: handle empty list in VirtualList. - Link your issue:
Closes #123in the PR body.
You get a review within 48 hours. Small PRs review faster.
- Does it break existing tests? A failing
bun run testblocks merge. - Is there a test for your change? Bug fixes need a test that would have caught the bug. New features need happy-path coverage and one edge case.
- Does it match existing style? Read a few files in the same package first.
- Are there
markDirty()calls? Any widget method you write that changes visible state callsmarkDirty(). - Is your commit message clear? Use:
fix(core): prevent layout overflow on zero-width boxorfeat(widgets): add BarChart widget.
type(scope): short description
Longer explanation if needed.
Fixes #123
Types: feat, fix, docs, refactor, test, chore, perf, style, a11y, ci, build, security
Scopes: core, widgets, ui, jsx, store, tss, router, motion, data, testing, dev-server, quick, create-termui-app, examples (the website scope lives in the separate TermUI_Docs repo)
The CI workflow auto-applies a type:* label from your PR title prefix. The label counts toward your GSSoC points.
- Create your file in the right package.
packages/widgets/src/for base widgets.packages/ui/src/for compound widgets. - Extend the
Widgetbase class from@termuijs/core. - Implement
_renderSelf(screen: Screen). - Call
this.markDirty()in every method you write that changes visual state. - Add a
caps.unicodefallback if you use non-ASCII characters. - Add a
caps.motionguard if your widget animates. - Export from the package's
index.ts. - Add tests. See
packages/widgets/src/data/Gauge.test.tsfor the pattern. - Add a doc page. The doc site lives in a separate repo: TermUI_Docs. Create your MDX in
src/content/. Register it insrc/content/pages.ts. Open the PR there.
- Create your
.tssfile inpackages/tss/src/themes/. - Add the theme name to
BUILTIN_THEMESinpackages/tss/src/themes/index.ts. - Update the theme count in
packages/tss/package.jsonandpackages/tss/README.md. - Update the TSS docs page.
TermUI participates in GSSoC 2026. Contribution window: 15 May to 14 August 2026. Below are the rules. Follow them to earn points.
This is required. PRs from contributors who do not star the repo fail the star-check job. The bot comments a reminder.
Star the repo, push any commit (or re-run the workflow), and the needs-star label lifts automatically.
Browse open good-first-issues.
Claim one. Comment:
I would like to work on this
The bot assigns you. You have 7 days to open your PR. After that the issue frees up.
One contributor holds at most 2 open issues. If you already have 2 assigned, the bot will not assign a third. Open and merge a PR from one of your current issues first. Then claim the next. This keeps work moving and gives every contributor a fair chance.
- Branch name:
type/short-description. - PR title:
type: short description. - Link your issue in the body:
Closes #N. - Fill in the PR template. Every section.
- All checks pass:
build,test,typecheck,star-check,auto-label.
Every approved PR earns points from labels. Your reviewer sets gssoc:approved plus level:* plus quality:* after review. type:* auto-applies from your PR title.
| Label | Effect |
|---|---|
gssoc:approved |
+50 base points. Required for any credit. |
level:beginner |
+20 difficulty |
level:intermediate |
+35 difficulty |
level:advanced |
+55 difficulty |
level:critical |
+80 difficulty |
quality:clean |
x 1.2 multiplier |
quality:exceptional |
x 1.5 multiplier |
type:docs |
+5 |
type:bug, type:feature, type:testing, type:design, type:refactor |
+10 |
type:accessibility, type:performance, type:devops |
+15 |
type:security |
+20 |
Formula: 50 + (difficulty x quality_multiplier) + type_bonus
Example: gssoc:approved + level:intermediate + quality:clean + type:feature = 50 + (35 x 1.2) + 10 = 102 pts.
These labels mean zero points and lead to disqualification:
gssoc:invalid. Your PR violates rules. Example: no linked issue, broken build, no tests, missing template fields.gssoc:spam. Duplicate, low-effort, or trivial change.gssoc:ai-slop. Generated content with no real engagement. Broken code or fabricated reasoning.
Do not:
- Submit a PR without claiming the issue first.
- Open multiple PRs for the same issue.
- Use AI to generate code you do not understand.
- Open PRs that only change whitespace or comments.
- Bundle unrelated changes.
Do:
- Engage with mentor feedback.
- Test your code locally before you open your PR.
- Read the existing code in your area.
- Ask questions on the GSSoC Discord when stuck.
- Quick questions: GSSoC Discord, project channel, tag
@Karanjot786. - PR-specific questions: comment on your PR with the exact line and error.
- Long-form or career: LinkedIn.
Format your question: "Hi, I am stuck on issue #42. Tried approach Y. Got error Z." Specific question = fast answer. "I'm stuck" = no answer.
| Day | Action |
|---|---|
| Monday | Pick one issue you finish this week. Claim it. |
| Wednesday | Open your PR. Ping your mentor if stuck. |
| Sunday | Check your rank on the GSSoC leaderboard. Plan next week. |
Open an issue or start a discussion. No question is stupid. The codebase has 14 packages and a lot of moving parts. Ask first, guess later.