concept

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Oct 22, 2026 License: MIT Imports: 6 Imported by: 0

Documentation

Overview

Package concept reads concept.md, the editorial brief of a newsletter: who it is for, what it promises, how each issue is built, how often it comes, how long it is, how it sounds, and when to worry. Sections are fixed, the words are the author's, and decisions cite research by ID (V012 a voice, P003 a peer newsletter, E101 evidence). A few lines are machine-readable ("Every: weekly", "Words: 400-900", "Use: …") so lfr can hold every issue to the brief.

Index

Constants

View Source
const (
	MinVoiceNotes = 8
	MinAxes       = 3
	MinFormat     = 2
	MaxFormat     = 8
	MinPillars    = 2
	MaxPillars    = 6
	MinExamples   = 3
	MinUse        = 2
	MinAvoid      = 2
)

Minimums the brief must meet.

View Source
const (
	RuleFormat   = "concept.format"
	RuleEvidence = "concept.evidence"
	RuleOpen     = "concept.open"
)

Rule IDs.

View Source
const File = "concept.md"

File is concept.md in the project root.

Variables

View Source
var Sections = []Spec{
	{"Diagnosis", true, "only when an existing newsletter is rebuilt: what works, what is generic, why readers stay or leave"},
	{"Reader", false, "who subscribes, where they come from, what they want from each issue"},
	{"Promise", false, "first line: one sentence of at most 160 characters for the signup page; then why it is credible"},
	{"Voices", false, "coded observations from the voices, each citing its IDs"},
	{"Axes", false, "table | Axis | Market | Readers | Chosen | where peers cluster and readers disagree"},
	{"Format", false, "numbered parts of a typical issue: 1. <part>: <job>"},
	{"Cadence", false, "Every: daily|weekly|biweekly|monthly|<n>d|<n>w, optional Day:, Time: HH:MM, Zone: <IANA>, and why it is sustainable"},
	{"Length", false, "Words: <min>-<max> for the body, and why"},
	{"Subject", false, "Max: <characters>, the style, and at least three Example: \"…\" lines"},
	{"Voice", false, "tone in prose, Use: \"…\" phrases from readers and Avoid: \"…\" words"},
	{"Pillars", false, "the recurring themes: - <name>: <what it covers>"},
	{"Signup", false, "Headline:, Pitch: and Frequency: for the website: what the form promises and how often mail comes"},
	{"Welcome", false, "what the welcome issue (welcome.md) says and why"},
	{"Growth", false, "how readers find the newsletter without paid ads"},
	{"Guardrails", false, "Unsubscribes: <n>% and Complaints: <n>% per issue that trigger a review, and what then"},
	{"Changelog", true, "dated changes and the research batch or learning behind them"},
}

Sections are the sections of concept.md in order.

Functions

func Citation

func Citation(text string) string

Citation strips research IDs from text, for fields shown to readers.

func Citations

func Citations(text string) []string

Citations returns the research IDs cited in text.

func ParseEvery

func ParseEvery(s string) (time.Duration, bool)

ParseEvery reads a cadence such as weekly or 3d.

func Rules

func Rules() []finding.Rule

Rules describes the concept checks.

Types

type Cadence

type Cadence struct {
	Every        time.Duration
	Label        string // as written
	Day          time.Weekday
	HasDay       bool
	Hour, Minute int
	HasTime      bool
	Zone         *time.Location
}

Cadence is how often issues go out.

func (Cadence) Next

func (c Cadence) Next(last, now time.Time) time.Time

Next returns the first send slot after last (the previous issue; zero for none) that is not before now: one cadence period later, moved to the brief's weekday and time in its zone.

type Concept

type Concept struct {
	Title        string
	Sections     map[string]*Section
	Promise      string
	Cadence      Cadence
	MinWords     int
	MaxWords     int
	MaxSubject   int
	Examples     []string
	Use          []string
	Avoid        []string
	Pillars      []string
	Headline     string
	Pitch        string
	Frequency    string  // how often mail comes, in the readers' language, shown at signup
	MaxUnsub     float64 // percent
	MaxComplaint float64 // percent
	Open         []Line
}

Concept is a parsed brief with its machine-readable fields.

func Parse

func Parse(text string, ids map[string]bool) (Concept, []finding.Finding)

Parse reads concept.md and reports format defects. ids are the citable research IDs; nil skips citation checks.

type Line

type Line struct {
	N    int
	Text string
}

Line is one source line.

type Section

type Section struct {
	Name  string
	Line  int
	Lines []Line
}

Section is the content under one "## " heading.

func (*Section) Field

func (s *Section) Field(key string) []Line

Field returns the values of "Key: value" lines in a section.

func (*Section) Text

func (s *Section) Text() string

Text joins a section's lines.

type Spec

type Spec struct {
	Name     string
	Optional bool
	Help     string
}

Spec is one section and whether it may be omitted.

Jump to

Keyboard shortcuts

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