Thanks for your interest in contributing! This document covers the workflow, conventions, and policies you need to know.
See Quick start in the README for prerequisites and setup instructions.
We use a Git Flow variant with two long-lived branches and short-lived topic branches.
main ← releases only (tagged)
develop ← integration branch (PRs land here)
└── feat/42/add-filter (your working branch)
| Branch | Purpose | Who merges |
|---|---|---|
main |
Stable releases. Always tagged. | Maintainers only |
develop |
Next-release integration | Anyone via PR |
topic (feat/…, fix/…, …) |
Individual changes | Author |
Format: {type}/{issue_no}/{short-desc}
| Type | Example |
|---|---|
feat |
feat/42/add-filter |
fix |
fix/108/stale-step-after-resume |
refactor |
refactor/65/split-proxy-module |
docs |
docs/71/cloudflare-setup |
chore |
chore/90/bump-deps |
- Create a branch from
develop:git checkout develop && git checkout -b feat/42/add-filter - Make your changes, commit, push.
- Open a Pull Request against
develop. - CI must pass. At least one maintainer review is required.
- Squash-merge into
develop.
When develop is ready for release, a maintainer merges develop into
main, tags the merge commit (e.g. v0.2.0), and fast-forward merges
main back into develop.
git checkout main && git merge --no-ff develop
git tag v0.2.0
git push origin main --tags
git checkout develop && git merge main
git push origin developDo not push directly to
mainordevelop. All changes go through PRs. Direct commits tomainare limited to release merges by maintainers.
Porta follows Semantic Versioning:
| Bump | When |
|---|---|
MAJOR |
Breaking changes to proxy API, config format, or CLI |
MINOR |
New features, new env vars, non-breaking proxy changes |
PATCH |
Bug fixes, documentation, dependency updates |
Releases are tagged on main (e.g. v0.1.0). The root package.json
and workspace packages share the same version number.
Pre-1.0: While the version is
0.x.y, minor bumps may contain breaking changes. This is standard SemVer practice.
Use Conventional Commits:
<type>(<scope>): <summary>
[optional body]
Types: feat, fix, refactor, docs, test, chore, ci
Scopes: proxy, web, or omit for repo-wide changes.
Examples:
feat(proxy): add workspace filtering to conversation list
fix(web): prevent stale steps after tab resume
docs: update Cloudflare tunnel setup instructions
- Keep PRs focused — one logical change per PR.
- Include a brief description of why, not just what.
- Link the related Issue: add
Closes #123in the PR description so the Issue is auto-closed on merge. - Update or add tests when changing behavior.
- Make sure
pnpm build && pnpm test && pnpm lintall pass locally before pushing.
When you open an Issue, GitHub will present you with a template chooser. Pick the one that fits:
| Template | Use when … |
|---|---|
| Bug Report | Something is broken or behaves unexpectedly |
| Feature Request | You want to propose a new feature or change |
| Blank issue | Anything else (question, discussion, etc.) |
- Security vulnerabilities: See SECURITY.md. Do not open a public Issue.
Maintainers apply labels during triage. The key labels are:
| Label | Meaning |
|---|---|
bug |
Confirmed defect |
enhancement |
Accepted feature request |
good first issue |
Suitable for new contributors |
triage |
Awaiting maintainer review |
priority/high |
Must be fixed before the next release |
priority/low |
Nice to have; no timeline pressure |
wontfix |
Declined — with explanation |
- A new Issue is automatically labelled
triage. - A maintainer reviews it, removes
triage, and applies the appropriate labels (bug/enhancement, priority, etc.). - If more information is needed the maintainer adds a comment and
applies
needs-info. The reporter has 14 days to respond before the Issue may be closed.
Issues with no activity for 60 days are marked stale. After a
further 14 days of inactivity they are closed automatically. Re-open
if the issue is still relevant.
Every code change should trace back to an Issue:
Issue #42 → branch feat/42/add-filter → PR "Closes #42"
This keeps the project history navigable and avoids orphan work.
- TypeScript strict mode is enabled for both
proxyandweb. - ESLint is configured for the
webpackage (pnpm lint). Theproxypackage does not have ESLint; it relies on TypeScript strict mode for static checks. - No additional formatter is enforced — match the style of surrounding code.
By contributing, you agree that your contributions will be licensed under the MIT License.