Skip to content

Contributing

Vladimir Kromm edited this page Sep 24, 2026 · 20 revisions

Contributing

How work gets proposed, built, and shipped — for me and for anyone else touching this public repo. See Vision for why; this page is about process, not direction.

Process

The aspiration

A mostly-automated delivery loop where owners role is approving tickets and approving PRs, not writing code day to day: a draft idea gets refined, estimated and implemented by set of abi83/interns agents and I do the final check and merge, focusing on product vision and strategy. Dev and prod are separate environments; prod only moves forward once new release is ready. Deterministic quality gates (automated tests, linting, type-checking, dependencies audit) help ensure quality, and the agents are held to the same bar as anyone else.

Trust boundary for a public repo

Anyone can open an issue or a PR here, but without owner direct approval issue cannot be processed, PR cannot be closed.

Interns pipeline

Issue tracking uses the refine → estimate → code → review flow from abi83/interns — labels, state machine, fix-round loop, per-agent tuning in .github/interns.yml all come from there directly.

What's specific to Prepify is the trust boundary: issues I write enter the interns pipeline automatically; issues opened by anyone else sit untouched until I've looked at them and brought them in myself (see above). Merge is always mine, regardless of who or what opened the PR.

Run metrics: abi83.github.io/prepify/interns-metrics

Code conventions

Process rules live here; how to write the code itself is binding on separate pages:

Read both before opening a coding-task PR.

Issues

Issue types

Issue types, labels, and templates follow abi83/interns conventions. Issue body follows its type:* template — don't pad it past what the template asks for.

Epics and sub-issues

Epic structure follows abi83/interns conventions. Only I create epics (or an agent when I explicitly ask). Every issue except bugs is a sub-issue of an epic — a coding-task or spike without a parent is invalid. Bugs can stand alone.

Two distinct native GitHub relations are in play — always use these; a plain-text #NN reference can be used as an additional (in-context) link, but not as a replacement:

Relation Tracks How to set
Sub-issue ("Parent issue") Epic membership Attach the issue as a sub-issue of the epic
"Blocked by" Execution order — what can't start before what Web UI, or gh api graphql with the addBlockedBy mutation (issueId + blockingIssueId, both GraphQL node IDs)

Closing and resolving

State what was actually done or found, and the resulting status, in a comment when closing an issue that didn't close via a normal PR merge — investigated and turned out not reproducible, superseded, decided against, etc. Don't close those silently. If the work produced follow-ups, link them by number — GitHub's sub-issue relation is parent/child only, so a lateral "this investigation led to that follow-up" link stays a plain #NN reference in text.

Pull requests

Commit and PR conventions

main is protected — no direct pushes, every change lands via a branch and a PR, no exceptions. PRs are squash-merged, so the PR title becomes the commit on main — write it as a Conventional Commit (feat:, fix:, refactor:, etc.). release-please reads that commit history on main to derive version bumps and the changelog; a non-conventional title is an invisible, unlabeled change to it.

Writing PR bodies

Keep them short and direct — the same conciseness bar as code and docs. Rationale, background, and root-cause analysis live on the issue; the PR says what changed and what to check.

PR body — three sections, nothing else:

  • What changed — bullets, the diff itself
  • Before merging — checklist of anything the PR depends on: a new Actions variable or secret, a migration to run, a setting to flip. Create it as part of the work and tick the box.
  • After merging — checklist of what to verify once it's live

A Notes section is for a genuine exception (a known follow-up needed, a deliberate deviation), not a routine part of every PR.

One PR, one concern

  • Something out of scope spotted mid-work — dead code, a stale doc, a second bug — gets offered as a follow-up PR or a ticket in Notes, not folded into the current branch and not left as an inline #fixme comment.
  • A reviewer comment that exposes a real gap (undocumented config, a missing test) gets fixed on the branch, not answered with a reply alone.

PR size and ticket linking

PR size (lines changed) Ticket required Native "Development" link required
≤10 No — straight to a fix: PR No
≤500 Yes Yes
≤1000 — ticket labeled size:XL Yes Yes

The reviewer pass and the owner merge always apply, regardless of size — only the ticket and linking requirements scale with it.

When a Development link is required, it covers:

  • the issue the PR implements
  • a followup issue the PR addresses
  • a bug ticket for a regression the PR fixes

If the PR fixes a bug that a prior PR introduced, also add a plain #NN reference to that prior PR — there's no native PR-to-PR link.

Definition of done

  • Every Acceptance Criteria checkbox is checked
  • Tests written for the change — placeholder until a real testing strategy exists (#78); once it does, this means whatever that strategy calls for
  • All automated checks green (build/test/lint in CI — more of these land as #78 progresses)
  • PR merged to main
  • Wiki updated if the change affects any documented behavior
  • For coding-task/bug: the change is verified actually working, not just green in isolation
  • For spikes: the decision and its Deliverable are written down somewhere durable (wiki/ADR), not just decided in someone's head

Verifying "actually working"

The goal: whichever agent implements a ticket does its best to exercise the real change itself, rather than treating green tests/type-checks as proof the feature itself works:

  • UI — drive a real browser: start the dev server, click through the actual flow, check console/network
  • Backend — make real API calls
  • Infra — run real terraform plan/state show or gcloud calls
  • Migrations — actually run it against dev and check the resulting schema

Deploying to dev first (not just running locally) is often the most realistic way to verify, especially for anything infra- or environment-dependent.

This is a direction to grow into, not a hard gate yet — the tooling to do this well (agents with browser/API/deploy access on every ticket) isn't fully wired up. Until it is: do as much of the above as the available tooling allows, and say explicitly what wasn't verified and why, rather than silently skipping it or claiming full verification that didn't happen.