conventions

package
v0.10.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 5, 2026 License: MIT Imports: 5 Imported by: 0

Documentation

Overview

Package conventions holds the tool's opinions: the label set, the issue body template, and the static primer text.

Index

Constants

View Source
const (
	// ProvenanceApply marks issues created by `hew apply`.
	ProvenanceApply = "apply"
	// ProvenanceMigrate marks issues created by `hew migrate beads`.
	ProvenanceMigrate = "migrate"
)

Batch writers stamp a provenance marker into every issue body they create so a later run can tell an issue it made from one it merely has a number for. Checkpoint state files are ordinary repository content and therefore untrusted: without a marker, a hand-written state file could point a mapping at any issue and the tool would wire, comment on, or close it (#81).

The marker binds three things, and verification requires all three:

  • the batch kind, so an apply mapping cannot be satisfied by a migrated issue or the reverse;
  • the source key (plan entry id, bead id), so a mapping cannot be redirected onto a different issue the same run created;
  • a digest of the source file, so an attacker who supplies their own plan or snapshot cannot claim issues created from the real one.

The digest is what makes the marker unforgeable in the case that matters. A marker is public, readable text, so anyone can copy one into an issue they control — but they cannot make an issue created from a different source file carry their digest.

View Source
const ClaudeSnippet = `## Issue tracking

Work is tracked in GitHub Issues via the ` + "`hew`" + ` CLI.
Run ` + "`hew prime`" + ` at session start — it prints the conventions,
the ready work, and current state. When in doubt: ` + "`hew ready`" + `.`

ClaudeSnippet is what `hew init` prints for the repo's CLAUDE.md: the point of prime is that the snippet stays this short.

View Source
const CodeSpanGuidance = "Write commands, flags, branch names, paths and error strings as code spans\n" +
	"(`--title`, `feat/pr-head`, `internal/cli/pr.go`, `go test -race ./...`): issue\n" +
	"and PR bodies are read in a browser and outlive the branch, and those are the\n" +
	"characters that blur into prose. Wrap the whole command, not just the flag\n" +
	"inside it. Composed bodies are checked and unmarked code text is warned about."

CodeSpanGuidance is the authoring rule the body templates prescribe. It is stated on the create/pr/apply help surfaces, but help text is read when someone goes looking for it and the composing agent generally does not — which is why the rule is also checked. UnmarkedCodeText is what makes it land; this text is what the warning points at.

View Source
const EpicTitlePrefix = "Epic: "

EpicTitlePrefix is the cosmetic title prefix the tool adds to parent issues. Epic-ness itself is defined by having sub-issues.

View Source
const PrimerStatic = `` /* 2750-byte string literal not displayed */

PrimerStatic is the conventions-and-cheatsheet half of `hew prime`, kept deliberately terse: the whole primer targets ~600 tokens.

Variables

View Source
var BranchPrefixes = []string{"feat/", "fix/", "chore/", "docs/"}

BranchPrefixes are the branch-name prefixes the workflow prescribes. A branch outside this set isn't refused — the work is already committed by the time a PR is opened — but it is warned about.

View Source
var CommitPrefixes = []string{"feat", "fix", "chore", "docs", "refactor", "test", "perf", "build", "ci", "style", "revert"}

CommitPrefixes are the conventional-commit prefixes a PR title may carry. The release changelog is grouped by them, so they are the reason the tool has an opinion about titles at all.

View Source
var Labels = buildLabels()

Labels is the convention label set `hew init` bootstraps: model's vocabulary (names) plus the cosmetics above. init creates the missing ones; color/description drift on labels that already exist is left alone — names are the contract, cosmetics are the repo owner's.

Functions

func DiscoveredFrom

func DiscoveredFrom(n int) string

DiscoveredFrom is the body line linking discovered work to its origin.

func FirstSection

func FirstSection(body string, names ...string) string

FirstSection returns the first non-empty of the named sections, so a caller can ask for a wording pair (Fix or Approach) in one go.

func FixesLine

func FixesLine(n int) string

FixesLine is the closing keyword GitHub links a merged PR to its issue by. Rendered in one place so the read-back check and the composed body can never drift apart.

func FixesReferences

func FixesReferences(body string) []int

FixesReferences returns the issue numbers a body already closes, in order of appearance, so the write path can enforce exactly one. It matches the closing keywords GitHub itself acts on (case-insensitively), not just the one this tool writes — a hand-written "Closes #7" links the PR just as hard as "Fixes #7", and silently adding a second link would close two issues on merge.

func FormatUnmarkedCodeText added in v0.8.0

func FormatUnmarkedCodeText(tokens []string) string

FormatUnmarkedCodeText renders the warning body for a set of findings, capping the list so a long body cannot bury the rest of the output.

func HasCommitPrefix

func HasCommitPrefix(title string) bool

HasCommitPrefix reports whether a title already carries a prefix.

func HasProvenanceMarker added in v0.9.0

func HasProvenanceMarker(body, kind, key, digest string) bool

HasProvenanceMarker reports whether body carries the marker for exactly this kind, key, and source digest.

func IsConventionalBranch

func IsConventionalBranch(branch string) bool

IsConventionalBranch reports whether a branch name carries one of the prescribed prefixes.

func PRTitle

func PRTitle(issueType, title string) string

PRTitle derives a PR title from the issue's type and title. A squash merge makes the PR title the commit subject, and the changelog is grouped by conventional-commit prefix — so a PR titled with the issue's own words lands the work under "Other" (#44). Issue titles deliberately carry no prefix (the type label holds that), which makes the type exactly the information the prefix encodes. An untyped issue gets no prefix: there is nothing to derive one from, and inventing one is worse than none.

func PartOfLine

func PartOfLine(n int) string

PartOfLine names the epic a sub-issue's PR belongs to.

func ProvenanceMarker added in v0.9.0

func ProvenanceMarker(kind, key, digest string) string

ProvenanceMarker returns the marker for one created issue: an HTML comment, so it carries no weight in the rendered body a human reads.

func Section

func Section(body, name string) string

Section extracts the content under a "### Name" header from an issue body, empty when absent. It lets the PR body be composed from what the issue already says instead of asking an agent to retype it.

func StripEmptySections

func StripEmptySections(body string) string

StripEmptySections removes template sections whose body is blank, so a half-filled skeleton posts clean. Non-template content is preserved verbatim.

func TemplateSections

func TemplateSections(issueType string) []string

TemplateSections returns the body-template section headers for a type, in order. Bugs describe a problem and a fix; enhancements and tasks a goal and an approach.

func TemplateSkeleton

func TemplateSkeleton(issueType string) string

TemplateSkeleton renders the empty template for --edit: headers with blank slots, "Done when" seeded with one checklist item.

func UnmarkedCodeText added in v0.8.0

func UnmarkedCodeText(body string) []string

UnmarkedCodeText returns the code-shaped tokens in a body that are not inside a code span or a fenced block, de-duplicated and in order of first appearance. It reports; it never rewrites.

Checking rather than transforming is the whole design. Marking text up automatically requires knowing what the text means — whether --body-file is a flag being named or part of "gh pr edit --body-file" — and that information is not in the token stream, so a transform splits compound commands and cannot be iterated out of it. The author knows. So the tool's job is to notice and say so, at the moment the body is composed, rather than to guess or to rely on help text having been read.

Reporting also inverts the cost of a false positive: a wrong rewrite ships permanently in a published body, while a wrong warning costs one line of stderr. That is what lets the checked set cover paths and identifiers, which no safe transform could ever touch.

Types

type Label

type Label struct {
	Name        string
	Color       string // hex, no leading #
	Description string
}

Label describes one label in the bootstrap set created by `hew init`.

type PRSections

type PRSections struct {
	What    string
	Why     string
	Testing string
}

PRSections are the pull-request body fields, mirroring the issue body template: What replaces the issue's Fix/Approach, Why its Problem/Goal, and Testing is the half an issue never carries.

func (PRSections) Compose

func (s PRSections) Compose(t PRTrailers) string

Compose renders the PR body: the provided sections in template order, then the trailers. Empty sections are omitted rather than left as bare headers, matching the issue template's rule.

func (PRSections) IsZero

func (s PRSections) IsZero() bool

IsZero reports whether no section was provided.

type PRTrailers

type PRTrailers struct {
	Fixes int
	Epic  int
}

PRTrailers are the tracker links that close the claim lifecycle: exactly one Fixes line so a merge closes the issue, plus the epic the issue hangs off, when it has one.

func (PRTrailers) Render

func (t PRTrailers) Render() string

Render returns the trailer block, empty when there is nothing to link. Both body paths go through it: the composed one renders the whole set, the --body-file one renders whatever the author didn't already write, so the escape hatch can't quietly lose a link the template would have made.

type Sections

type Sections struct {
	Where    string
	Problem  string
	Goal     string
	Fix      string
	Approach string
	DoneWhen []string
}

Sections are the structured body fields carried by the create section flags and plan entries. Problem/Goal and Fix/Approach are wording pairs — at most one of each is set (the write path enforces it), and whichever is set picks the header, so word choice is never policed against the issue type.

func (Sections) Compose

func (s Sections) Compose() string

Compose renders the sections as a template-conformant body: headers in template order, provided sections only, Done when as a checklist.

func (Sections) IsZero

func (s Sections) IsZero() bool

IsZero reports whether no section was provided.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL