From 2b4bd2aaaf030df970cc11d5e4844c00f0123ca8 Mon Sep 17 00:00:00 2001 From: Cory LaNou Date: Sun, 15 Mar 2026 13:19:24 -0500 Subject: [PATCH] feat: add 4 tutorial blog posts for usage scenario series - Training Materials: building reusable course content with includes - Engineering Handbook: automated internal docs that stay in sync - Release Notes Pipeline: validated release notes with executable examples - AI-Assisted Authoring: combining AI speed with build-time validation Partial progress on #3 --- content/ai-authoring-workflow/module.md | 318 +++++++++++++++++++ content/engineering-handbook/module.md | 330 +++++++++++++++++++ content/release-notes-pipeline/module.md | 386 +++++++++++++++++++++++ content/training-materials/module.md | 310 ++++++++++++++++++ 4 files changed, 1344 insertions(+) create mode 100644 content/ai-authoring-workflow/module.md create mode 100644 content/engineering-handbook/module.md create mode 100644 content/release-notes-pipeline/module.md create mode 100644 content/training-materials/module.md diff --git a/content/ai-authoring-workflow/module.md b/content/ai-authoring-workflow/module.md new file mode 100644 index 0000000..38c4b75 --- /dev/null +++ b/content/ai-authoring-workflow/module.md @@ -0,0 +1,318 @@ +# AI-Assisted Authoring with Hype + +
+slug: ai-authoring-workflow +published: 03/15/2026 +author: Cory LaNou +seo_description: Learn how to combine AI coding assistants like Claude with Hype's build-time validation to write technical documentation faster while keeping every code example correct. +tags: tutorial, ai, authoring, workflow, claude, hype +
+ +AI assistants are transforming how we write code. But when it comes to technical documentation, there's a trust problem: AI can generate plausible-looking code examples that don't actually work. Hype solves this by validating everything at build time — making AI-generated content trustworthy through automated verification. + +This guide shows how to combine AI authoring with Hype's validation to write better documentation, faster. + +## The Trust Problem + +When an AI generates a code example for your documentation, it might: + +- Use an API that was renamed two versions ago +- Import a package that doesn't exist +- Show output that doesn't match what the code actually produces +- Use syntax that's almost right but won't compile + +In a regular Markdown file, these errors are invisible until a reader tries the code. In a Hype document, the build catches them immediately. + +## The Workflow + +The AI-assisted Hype authoring workflow has three phases: + +1. **Generate** — AI writes the prose and code examples +2. **Validate** — Hype builds the document, catching errors +3. **Iterate** — AI fixes what the build caught + +This is fundamentally different from the "generate and ship" workflow that produces unreliable documentation. + +### Phase 1: Generate the Structure + +Start by asking your AI assistant to create the document structure with real source files. The key instruction: **code examples must be separate `.go` files, not inline code blocks.** + +For example, ask Claude: + +> "Write a tutorial about Go's context package. Create the example code as separate Go files in a src/ directory, and reference them with Hype's include syntax." + +The AI generates: + +``` +context-tutorial/ +├── hype.md +└── src/ + ├── basic/main.go + ├── timeout/main.go + ├── cancel/main.go + └── values/main.go +``` + +Each source file is a complete, runnable program. The `hype.md` references them with `` and `` tags. + +### Phase 2: Build and Catch Errors + +Run the build: + +```bash +hype export -format markdown -f hype.md > /dev/null +``` + +The build might fail with something like: + +``` +Error: filepath: hype.md +document: Context Tutorial +execute error: src/timeout/main.go:15: + ctx.WithTimeout undefined (type context.Context has no method WithTimeout) +``` + +The AI used `ctx.WithTimeout()` instead of `context.WithTimeout()`. A plausible mistake that a human reviewer might miss, but the compiler catches instantly. + +### Phase 3: Fix and Rebuild + +Give the error back to the AI: + +> "The build failed. `context.WithTimeout` is a package-level function, not a method on Context. Fix src/timeout/main.go." + +The AI fixes the code. You rebuild. The cycle continues until the build succeeds, at which point every code example in the document is verified correct. + +## Practical Example: Writing a Package Tutorial + +Let's walk through writing a complete tutorial using this workflow. + +### Step 1: Set Up the Project + +```bash +mkdir errors-tutorial && cd errors-tutorial +mkdir -p src/{wrapping,sentinel,custom,unwrap} +``` + +### Step 2: AI Generates the Content + +Ask the AI to write the tutorial. Provide these constraints: + +- Each concept gets its own subdirectory under `src/` +- Every Go file must be a complete `package main` with a `main()` function +- Use `` tags to both show the code and run it +- Use snippets to highlight specific parts + +The AI generates `hype.md`: + +```markdown +# Effective Error Handling in Go + +## Wrapping Errors + +The `%w` verb in `fmt.Errorf` wraps an error, preserving the +original for inspection: + +<go src="src/wrapping" run="." code="main.go#wrap-example"></go> + +## Sentinel Errors + +Define package-level sentinel errors for conditions callers +need to check: + +<go src="src/sentinel" run="." code="main.go#sentinel-def"></go> + +## Custom Error Types + +Implement the `error` interface for errors that carry +structured data: + +<go src="src/custom" run="." code="main.go"></go> + +## Unwrapping and Checking + +Use `errors.Is` and `errors.As` to inspect wrapped errors: + +<go src="src/unwrap" run="." code="main.go"></go> +``` + +And the source files: + +```go +// src/wrapping/main.go +package main + +import ( + "errors" + "fmt" +) + +// snippet: wrap-example +func readConfig(path string) error { + err := errors.New("file not found") + return fmt.Errorf("readConfig(%q): %w", path, err) +} +// snippet: wrap-example + +func main() { + err := readConfig("/etc/app.conf") + fmt.Println(err) + fmt.Println("Unwrapped:", errors.Unwrap(err)) +} +``` + +```go +// src/sentinel/main.go +package main + +import ( + "errors" + "fmt" +) + +// snippet: sentinel-def +var ( + ErrNotFound = errors.New("resource not found") + ErrUnauthorized = errors.New("unauthorized access") + ErrRateLimit = errors.New("rate limit exceeded") +) +// snippet: sentinel-def + +func findUser(id int) error { + if id <= 0 { + return fmt.Errorf("findUser: %w", ErrNotFound) + } + return nil +} + +func main() { + err := findUser(-1) + if errors.Is(err, ErrNotFound) { + fmt.Println("User not found (expected)") + } +} +``` + +### Step 3: Build + +```bash +hype export -format markdown -f hype.md +``` + +If everything compiles and runs, you have a validated tutorial. If not, the error tells you exactly what to fix. + +### Step 4: Review and Refine + +With the code validated, focus your review on: + +- **Prose quality** — is the explanation clear and accurate? +- **Pedagogical flow** — do concepts build on each other logically? +- **Completeness** — are edge cases covered? + +You don't need to manually verify that code examples work. The build already did that. + +## Tips for AI-Assisted Hype Authoring + +### Give the AI the Right Constraints + +The most important instruction is to keep code in separate files: + +> "Write code examples as standalone Go files in src/ subdirectories. Each must be a complete program that compiles and runs. Reference them with Hype `` and `` tags in the markdown." + +### Use Snippets to Focus + +AI-generated examples often include boilerplate. Use snippets to show only the relevant part: + +> "Add snippet markers around the key function so the tutorial can show just that function while the full file still compiles." + +### Let the Build Be the Reviewer + +Don't spend time manually checking code examples. Build the document. If it passes, the code is correct. If it fails, the error message tells you exactly what's wrong. + +### Iterate Quickly + +The AI → build → fix cycle is fast: + +1. AI generates or modifies a file +2. `hype export` runs in seconds +3. Error goes back to the AI +4. Repeat until green + +A typical tutorial with 5-10 code examples goes from first draft to fully validated in a few minutes. + +### Version Pin Your Examples + +When the AI generates code, ask it to use specific versions: + +> "Use Go 1.22's range-over-func feature. Make sure the go.mod specifies go 1.22." + +This ensures the examples are reproducible and won't break with Go version changes. + +## Stabilizing Dynamic Output + +AI assistants often produce examples with dynamic output (timestamps, UUIDs, etc.). Use Hype's replace attributes to stabilize: + +```html +<cmd exec="go run ./src/timestamp" + replace-1="\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}" + replace-1-with="2024-01-15T10:30:00"></cmd> +``` + +The command runs (validating it works), but the output is deterministic in the final document. No more noisy diffs from regenerating docs. + +## CI Integration + +Add validation to your CI pipeline so AI-generated docs are checked on every push: + +```yaml +name: Validate Documentation +on: [push, pull_request] + +jobs: + validate: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version-file: go.mod + - run: go install github.com/gopherguides/hype/cmd/hype@main + + - name: Build all tutorials + run: | + for doc in */hype.md; do + dir=$(dirname "$doc") + echo "Building ${dir}..." + (cd "$dir" && hype export -format markdown -f hype.md > /dev/null) + done +``` + +This catches regressions: if a Go update breaks an example, the CI build fails and you know exactly which document needs updating. + +## What This Unlocks + +The combination of AI authoring speed and Hype validation changes what's practical: + +- **Write a tutorial in minutes, not hours** — AI generates the structure and examples, Hype verifies correctness +- **Update docs with confidence** — regenerate after dependency changes, the build catches every broken example +- **Scale documentation** — producing 10 validated tutorials is only slightly more work than producing 1 +- **Trust AI-generated content** — the compiler is the reviewer, not a human scanning for plausible-but-wrong code + +## Key Takeaways + +- **AI generates, Hype validates** — plausible-looking code is verified by the compiler +- **Separate files, not inline code** — keep examples as real Go files that compile independently +- **Fast iteration cycles** — generate, build, fix, repeat until green +- **Focus human review on prose** — let the build handle code correctness +- **CI catches regressions** — automated builds surface broken examples from dependency changes +- **Stabilize dynamic output** — replace patterns keep regenerated docs diff-friendly + +## Get Started + +```bash +brew install gopherguides/tap/hype + +mkdir my-tutorial && cd my-tutorial +mkdir -p src/example +``` + +Write your first AI-assisted tutorial. Ask the AI to create a Go example as a separate file, reference it with a `` tag, and build. When the build passes, you have documentation you can trust. diff --git a/content/engineering-handbook/module.md b/content/engineering-handbook/module.md new file mode 100644 index 0000000..58ede42 --- /dev/null +++ b/content/engineering-handbook/module.md @@ -0,0 +1,330 @@ +# Automating Your Engineering Handbook with Hype + +
+slug: engineering-handbook +published: 03/15/2026 +author: Cory LaNou +seo_description: Use Hype to build an internal engineering handbook that stays in sync with your codebase. Executable examples, automated validation, and single-source documentation for your team. +tags: tutorial, engineering, handbook, automation, hype +
+ +Every engineering team has internal documentation. Style guides, onboarding docs, architecture decision records, runbook procedures. And almost universally, that documentation is wrong. Not because someone wrote it badly, but because the code changed and nobody updated the docs. + +Hype fixes this by making your internal documentation a build artifact — derived from your actual code, validated at build time, and updated automatically. + +## What Goes in an Engineering Handbook + +A typical engineering handbook covers: + +- **Coding standards** — naming conventions, error handling patterns, testing requirements +- **Architecture guides** — how services communicate, data flow, deployment topology +- **Onboarding** — environment setup, tooling, first-week checklist +- **Runbooks** — incident response procedures, common debugging commands +- **API documentation** — internal service contracts, request/response examples + +All of these reference code. And all of them go stale. + +## Project Structure + +Here's how to organize a Hype-powered handbook: + +``` +handbook/ +├── hype.md # Master handbook +├── config.yaml # Hype blog config (for web output) +├── content/ +│ ├── onboarding/ +│ │ ├── hype.md +│ │ └── src/ +│ │ └── setup.sh +│ ├── coding-standards/ +│ │ ├── hype.md +│ │ └── src/ +│ │ ├── good/main.go +│ │ └── bad/main.go +│ ├── architecture/ +│ │ ├── hype.md +│ │ └── diagrams/ +│ ├── runbooks/ +│ │ ├── hype.md +│ │ └── src/ +│ │ └── healthcheck.sh +│ └── api/ +│ ├── hype.md +│ └── src/ +│ └── examples/ +└── shared/ + └── conventions.md +``` + +## Coding Standards That Prove Themselves + +The most powerful use of Hype in a handbook is coding standards that include real examples — both good and bad — with actual compiler and linter output. + +### Good Examples That Compile + +```go +// content/coding-standards/src/good/main.go +package main + +import ( + "errors" + "fmt" +) + +// snippet: error-handling +func fetchUser(id int) (*User, error) { + user, err := db.GetUser(id) + if err != nil { + return nil, fmt.Errorf("fetchUser(%d): %w", id, err) + } + return user, nil +} +// snippet: error-handling + +// snippet: sentinel-errors +var ( + ErrNotFound = errors.New("not found") + ErrUnauthorized = errors.New("unauthorized") +) +// snippet: sentinel-errors +``` + +In your handbook: + +```markdown +## Error Handling + +Always wrap errors with context using `fmt.Errorf` and the `%w` verb: + +<code src="src/good/main.go" snippet="error-handling"></code> + +Use sentinel errors for conditions that callers need to check: + +<code src="src/good/main.go" snippet="sentinel-errors"></code> +``` + +These examples compile. If someone changes the error handling API in a dependency update, the build catches it. + +### Bad Examples That Intentionally Fail + +Show anti-patterns with their actual compiler errors: + +```go +// content/coding-standards/src/bad/main.go +package main + +// snippet: unused-error +func riskyOperation() { + result, _ := dangerousCall() + fmt.Println(result) +} +// snippet: unused-error +``` + +```markdown +## What NOT To Do + +Never discard errors with the blank identifier: + +<code src="src/bad/main.go" snippet="unused-error"></code> + +Here's what the linter says about this: + +<cmd exec="staticcheck ./src/bad/..." exit="1"></cmd> +``` + +The `exit="1"` attribute tells Hype that this command is expected to fail. The linter output is captured and included in the document, showing the team exactly why this pattern is flagged. + +## Onboarding Documentation + +New engineer onboarding docs are notoriously fragile. "Run this command" instructions break when tools update, environment variables change, or infrastructure moves. + +### Executable Setup Scripts + +Instead of documenting commands in Markdown, keep them in an actual script: + +```bash +#!/bin/bash +# content/onboarding/src/setup.sh + +# Check Go version +go version + +# Check Docker +docker --version + +# Check kubectl +kubectl version --client + +# Clone the monorepo +# git clone git@github.com:yourorg/monorepo.git + +# Install development tools +go install golang.org/x/tools/gopls@latest +go install honnef.co/go/tools/cmd/staticcheck@latest +``` + +Reference it in the onboarding guide: + +```markdown +## Development Environment Setup + +Run the setup script to verify your environment: + +<code src="src/setup.sh"></code> + +Here's what the output should look like on a properly configured machine: + +<cmd exec="bash src/setup.sh"></cmd> +``` + +When you build the handbook, Hype runs the setup script and captures the output. If any tool is missing from the CI environment, the build fails — telling you the onboarding docs need updating. + +## Runbooks with Validated Commands + +Runbooks are critical during incidents. A wrong command in a runbook can make things worse. Hype ensures every command in your runbook actually works. + +### Health Check Runbook + +```bash +#!/bin/bash +# content/runbooks/src/healthcheck.sh + +echo "=== Service Health Check ===" + +# Check if the service is responding +echo "API Status:" +curl -s -o /dev/null -w "%{http_code}" http://localhost:8080/health || echo "UNREACHABLE" + +# Check database connectivity +echo -e "\nDatabase:" +pg_isready -h localhost -p 5432 2>/dev/null && echo "OK" || echo "NOT READY" + +# Check disk space +echo -e "\nDisk Space:" +df -h / | tail -1 | awk '{print $5 " used"}' + +# Check memory +echo -e "\nMemory:" +free -h 2>/dev/null | grep Mem || vm_stat 2>/dev/null | head -5 +``` + +```markdown +## Incident Response: Health Check + +When paged, start with the health check script: + +<code src="src/healthcheck.sh"></code> + +Interpret the output: + +| Check | Healthy | Action if unhealthy | +|-------|---------|-------------------| +| API Status | 200 | Check service logs, restart if needed | +| Database | OK | Check connection string, verify DB is running | +| Disk Space | < 80% | Clear logs, expand volume | +| Memory | < 90% | Check for memory leaks, restart service | +``` + +## Architecture Documentation with Go Doc + +Hype can include `go doc` output directly in your handbook, keeping API documentation current: + +```markdown +## Package API Reference + +### The `auth` Package + +<go doc="-short ./internal/auth"></go> + +### Key Types + +<go doc="./internal/auth.Token"></go> + +<go doc="./internal/auth.Claims"></go> +``` + +Every time you build, `go doc` reflects the current code. When someone adds a method or changes a type signature, the handbook updates automatically. + +## Building and Deploying + +### As a Static Site + +Use Hype's blog generator to serve the handbook as an internal website: + +```bash +hype blog init handbook +# Move your content into the blog structure +hype blog build +hype blog serve +``` + +Deploy behind your VPN or internal network. Every push to the handbook repo triggers a rebuild and redeploy. + +### As a Single Document + +Generate a single comprehensive document: + +```bash +# HTML for internal wiki +hype export -format html -f hype.md > handbook.html + +# Markdown for GitHub/GitLab wiki +hype export -format markdown -f hype.md > HANDBOOK.md +``` + +### CI Validation + +Add validation to your CI pipeline: + +```yaml +name: Validate Handbook +on: + push: + paths: + - 'handbook/**' + schedule: + - cron: '0 9 * * 1' # Weekly Monday build + +jobs: + validate: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version-file: go.mod + - run: go install github.com/gopherguides/hype/cmd/hype@main + - run: cd handbook && hype export -format html -f hype.md > /dev/null +``` + +The scheduled weekly build catches drift even when nobody is actively editing the handbook. If a dependency update breaks an example, you'll know on Monday morning instead of during an incident. + +## Keeping It Alive + +The biggest challenge with internal documentation isn't writing it — it's keeping it current. Hype addresses this by making staleness visible: + +1. **Build failures are documentation bugs** — when code changes break the handbook build, you fix the docs as part of the code change +2. **Weekly CI builds catch drift** — scheduled builds surface problems even when the handbook isn't actively edited +3. **Pull request previews** — require handbook updates in the same PR that changes the code it documents +4. **Single source of truth** — code examples come from real files, not copy-pasted blocks that diverge + +## Key Takeaways + +- **Standards that compile** — coding guidelines backed by real examples the compiler validates +- **Onboarding that works** — setup scripts that run in CI, not just in the README +- **Runbooks you can trust** — commands validated before they're needed at 3 AM +- **Auto-updating API docs** — `go doc` output that reflects the current code +- **Drift detection** — scheduled builds catch stale docs before they cause problems + +## Get Started + +```bash +brew install gopherguides/tap/hype + +mkdir handbook && cd handbook +mkdir -p content/coding-standards/src/{good,bad} +``` + +Start with your coding standards — they're the easiest to validate and the most impactful to keep current. Add one real code example, build, and expand from there. diff --git a/content/release-notes-pipeline/module.md b/content/release-notes-pipeline/module.md new file mode 100644 index 0000000..1dc6e69 --- /dev/null +++ b/content/release-notes-pipeline/module.md @@ -0,0 +1,386 @@ +# Building a Release Notes Pipeline with Hype + +
+slug: release-notes-pipeline +published: 03/15/2026 +author: Cory LaNou +seo_description: Build a release notes pipeline using Hype with executable code snippets, automated validation, and version-aware documentation that ships with every release. +tags: tutorial, release-notes, ci-cd, pipeline, hype +
+ +Release notes are the first thing users read after updating. Bad release notes — outdated examples, broken migration commands, incorrect API signatures — erode trust and generate support tickets. Hype lets you build release notes where every code example compiles, every command runs, and every API reference reflects the actual release. + +## Why Release Notes Break + +Traditional release notes are written in a Markdown file, usually by copying code snippets from the diff, manually running commands to verify output, and hoping someone catches mistakes in review. This breaks because: + +- **Code examples are copy-pasted** — they're not validated against the actual build +- **Migration commands are written from memory** — they might work on the author's machine but not fresh installs +- **API signatures are typed by hand** — typos and outdated signatures slip through +- **Version numbers are hardcoded** — someone always forgets to update one + +## Project Structure + +Here's how to structure release notes as a Hype project: + +``` +releases/ +├── v1.5.0/ +│ ├── hype.md # Release notes source +│ ├── src/ +│ │ ├── new-feature/main.go # New feature example +│ │ ├── migration/main.go # Migration example +│ │ └── breaking/main.go # Breaking change example +│ └── scripts/ +│ ├── migrate.sh # Migration script +│ └── verify.sh # Verification script +├── v1.4.0/ +│ └── ... +└── template/ + ├── hype.md # Release notes template + └── shared/ + └── footer.md # Standard footer +``` + +Each release gets its own directory with real, compilable code examples and runnable scripts. + +## Writing Release Notes with Hype + +### New Feature: Executable Examples + +When documenting a new feature, include a working example that demonstrates it: + +```go +// src/new-feature/main.go +package main + +import ( + "fmt" + "yourpackage/v2/config" +) + +func main() { + // snippet: basic-usage + cfg, err := config.Load("app.yaml", + config.WithDefaults(), + config.WithEnvOverrides("APP_"), + ) + if err != nil { + fmt.Printf("Error: %v\n", err) + return + } + fmt.Printf("Loaded %d settings\n", cfg.Len()) + // snippet: basic-usage +} +``` + +Reference it in your release notes: + +```markdown +## New: Configuration Loading API + +The new `config.Load` function supports option chaining +for cleaner configuration setup: + +<code src="src/new-feature/main.go" snippet="basic-usage"></code> + +Running this with a sample config file: + +<go src="src/new-feature" run="."></go> +``` + +When you build these release notes, Hype compiles the example against your actual package and runs it. If the API changed since you wrote the notes, the build fails. + +### Migration Guides: Validated Step by Step + +Migration instructions are the most critical part of release notes. A wrong command during migration can cause data loss. Validate every step: + +```bash +#!/bin/bash +# src/scripts/migrate.sh + +echo "=== Migration from v1.4 to v1.5 ===" + +# Step 1: Update the dependency +echo "Step 1: Updating dependency..." +go get yourpackage/v2@v1.5.0 + +# Step 2: Run the migration tool +echo "Step 2: Running schema migration..." +go run ./cmd/migrate --from=v1.4 --to=v1.5 --dry-run + +# Step 3: Verify +echo "Step 3: Verifying..." +go run ./cmd/verify +``` + +```markdown +## Migration Guide + +Follow these steps to migrate from v1.4 to v1.5: + +<code src="scripts/migrate.sh"></code> + +Expected output on a successful migration: + +<cmd exec="bash scripts/migrate.sh"></cmd> + +If you see errors at Step 2, check the +[troubleshooting guide](/docs/troubleshooting/). +``` + +The migration script runs in CI. If the commands don't work against the current release, you find out before users do. + +### Breaking Changes: Show the Compiler Error + +When documenting breaking changes, show users exactly what they'll see and how to fix it: + +```go +// src/breaking/old/main.go +package main + +import "yourpackage/v2/auth" + +// snippet: old-way +func authenticate(token string) bool { + // This no longer compiles in v1.5 + return auth.Verify(token) +} +// snippet: old-way +``` + +```go +// src/breaking/new/main.go +package main + +import ( + "context" + "yourpackage/v2/auth" +) + +// snippet: new-way +func authenticate(ctx context.Context, token string) (*auth.Claims, error) { + return auth.Verify(ctx, token) +} +// snippet: new-way +``` + +```markdown +## Breaking Changes + +### `auth.Verify` Now Requires Context + +**Before (v1.4):** + +<code src="src/breaking/old/main.go" snippet="old-way"></code> + +Compiling old code produces: + +<go src="src/breaking/old" run="." exit="1"></go> + +**After (v1.5):** + +<code src="src/breaking/new/main.go" snippet="new-way"></code> +``` + +The `exit="1"` attribute tells Hype the old code is expected to fail. Users see the exact compiler error they'll encounter, making it easy to find and fix their code. + +### Version Information: Dynamic, Not Hardcoded + +Use command execution to include version information dynamically: + +```markdown +## Version Information + +<cmd exec="go run ./cmd/tool version" + replace-1="v\d+\.\d+\.\d+" + replace-1-with="v1.5.0"></cmd> + +Built with: + +<cmd exec="go version" + replace-1="go\d+\.\d+\.\d+" + replace-1-with="go1.22.0"></cmd> +``` + +The `replace` attributes stabilize dynamic output. The actual command runs (validating it works), but version strings are normalized so the output doesn't change with every Go patch release. + +## Automating the Pipeline + +### CI Workflow for Release Notes + +Validate release notes as part of your release process: + +```yaml +name: Validate Release Notes +on: + push: + paths: + - 'releases/**' + pull_request: + paths: + - 'releases/**' + +jobs: + validate: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version-file: go.mod + - run: go install github.com/gopherguides/hype/cmd/hype@main + + - name: Validate all release notes + run: | + for release in releases/*/hype.md; do + dir=$(dirname "$release") + echo "Validating ${dir}..." + cd "$dir" + hype export -format markdown -f hype.md > /dev/null + cd - + done + + - name: Build latest release notes + run: | + latest=$(ls -d releases/v* | sort -V | tail -1) + cd "$latest" + hype export -format html -f hype.md > release-notes.html + + - uses: actions/upload-artifact@v4 + with: + name: release-notes + path: releases/*/release-notes.html +``` + +### Generate Multiple Formats + +Produce release notes in every format your users need: + +```bash +#!/bin/bash +# scripts/build-release-notes.sh + +VERSION="${1:?Usage: build-release-notes.sh }" +DIR="releases/${VERSION}" + +if [ ! -f "${DIR}/hype.md" ]; then + echo "No release notes found for ${VERSION}" + exit 1 +fi + +cd "$DIR" + +# HTML for the website +hype export -format html -f hype.md > release-notes.html + +# Markdown for GitHub release +hype export -format markdown -f hype.md > RELEASE.md + +echo "Built release notes for ${VERSION}" +``` + +### Integrate with GitHub Releases + +Automate GitHub release creation with validated release notes: + +```yaml +name: Create Release +on: + push: + tags: + - 'v*' + +jobs: + release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version-file: go.mod + - run: go install github.com/gopherguides/hype/cmd/hype@main + + - name: Build release notes + run: | + VERSION=${GITHUB_REF_NAME} + cd "releases/${VERSION}" + hype export -format markdown -f hype.md > RELEASE.md + + - name: Create GitHub Release + uses: softprops/action-gh-release@v1 + with: + body_path: releases/${{ github.ref_name }}/RELEASE.md +``` + +Push a tag, the workflow builds the release notes (validating all examples), and creates the GitHub release with the generated Markdown. + +## Release Notes Template + +Start each release with a template that ensures consistency: + +```markdown + +# Release vX.Y.Z + +Released: [DATE] + +## Highlights + +[2-3 sentence summary of the most impactful changes] + +## New Features + +### [Feature Name] + +[Description] + +<code src="src/feature/main.go" snippet="example"></code> + +## Improvements + +- [Improvement 1] +- [Improvement 2] + +## Breaking Changes + +### [Change Description] + +**Before:** + +<code src="src/breaking/old.go" snippet="old"></code> + +**After:** + +<code src="src/breaking/new.go" snippet="new"></code> + +## Migration Guide + +<code src="scripts/migrate.sh"></code> + +## Bug Fixes + +- [Fix 1] +- [Fix 2] + +<include src="../shared/footer.md"></include> +``` + +## Key Takeaways + +- **Every example compiles** — code in release notes is validated against the actual release +- **Migration commands run** — scripts are executed in CI, not just documented +- **Breaking changes show real errors** — users see exact compiler messages they'll encounter +- **Dynamic version info** — command output is captured live, not typed by hand +- **Automated pipeline** — tag a release and get validated, multi-format release notes automatically +- **Templates ensure consistency** — every release follows the same structure + +## Get Started + +```bash +brew install gopherguides/tap/hype + +mkdir -p releases/v1.0.0/src/feature +``` + +Start with your next release. Write one feature example as real code, include it in the notes, and build. Once you see a broken example caught at build time, you'll never go back to hand-written release notes. diff --git a/content/training-materials/module.md b/content/training-materials/module.md new file mode 100644 index 0000000..926ba01 --- /dev/null +++ b/content/training-materials/module.md @@ -0,0 +1,310 @@ +# Building Training Materials with Hype + +
+slug: training-materials +published: 03/15/2026 +author: Cory LaNou +seo_description: Learn how to use Hype to build reusable training and course materials with executable code examples, file includes, and modular content that stays in sync with your codebase. +tags: tutorial, training, education, includes, hype +
+ +If you've ever written training materials for a programming course, you know the pain: code examples go stale, exercises drift out of sync with the slides, and updating one module means checking every other module that references it. Hype was built to solve exactly this problem. + +This guide shows how to use Hype's include system and code execution to build training materials that are modular, reusable, and always up to date. + +## The Problem with Traditional Course Materials + +A typical Go training course might have 20 modules. Each module has: + +- Lecture notes with code examples +- Exercises with starter code +- Solutions with expected output +- Slides summarizing key points + +When Go releases a new version and a stdlib API changes, you have to find and update every reference across all 20 modules. When a student reports that an exercise doesn't compile, you have to figure out which version of the code is current. When you reuse a concept explanation across modules, you end up with slightly different versions that diverge over time. + +## The Hype Approach + +With Hype, your course materials are structured like a codebase: + +``` +training/ +├── hype.md # Master document +├── modules/ +│ ├── 01-basics/ +│ │ ├── hype.md # Module document +│ │ ├── notes.md # Lecture notes +│ │ └── src/ +│ │ ├── hello/main.go # Example code +│ │ └── exercise/main.go +│ ├── 02-types/ +│ │ ├── hype.md +│ │ ├── notes.md +│ │ └── src/ +│ │ ├── types/main.go +│ │ └── exercise/main.go +│ └── 03-functions/ +│ ├── hype.md +│ ├── notes.md +│ └── src/ +│ ├── functions/main.go +│ └── exercise/main.go +└── shared/ + ├── setup.md # Reusable setup instructions + ├── go-install.md # Go installation guide + └── src/ + └── common/helpers.go # Shared example code +``` + +Each module is self-contained with its own source files, but can include shared content. The master document pulls everything together. + +## Building a Module + +### Step 1: Write the Example Code + +Start with real, compilable Go code. Put it in the module's `src/` directory: + +```go +// src/hello/main.go +package main + +import "fmt" + +func main() { + fmt.Println("Hello, training participant!") +} +``` + +This is actual source code that the Go compiler validates. It's not a code block in a Markdown file — it's a real `.go` file. + +### Step 2: Reference It in Your Module + +Create the module's `hype.md`: + +```markdown +# Module 1: Go Basics + +## Your First Go Program + +Here's a simple Go program that prints a greeting: + +<code src="src/hello/main.go"></code> + +Let's run it and see the output: + +<go src="src/hello" run="."></go> +``` + +When you build this module, Hype: + +1. Includes the contents of `src/hello/main.go` as a syntax-highlighted code block +2. Runs `go run .` in the `src/hello` directory +3. Captures the output and includes it in the document + +If the code doesn't compile, the build fails. You'll never ship broken examples to students. + +### Step 3: Add Exercises + +Create exercise code with intentional gaps for students to fill in: + +```go +// src/exercise/main.go +package main + +import "fmt" + +func main() { + // TODO: Print your name using fmt.Println +} +``` + +Reference it in your module document: + +```markdown +## Exercise: Hello You + +Complete the following program to print your name: + +<code src="src/exercise/main.go"></code> + +**Expected output:** + +``` +Hello, [Your Name]! +``` +``` + +The exercise code compiles (it just doesn't do anything useful yet), so the build still succeeds. Students get a validated starting point. + +## Using Includes for Shared Content + +Training materials often repeat the same setup instructions, environment requirements, or concept explanations. Hype's `` tag lets you write these once and reference them everywhere. + +### Shared Setup Instructions + +Create a shared setup file: + +```markdown + +## Environment Setup + +Before starting this module, make sure you have: + +1. Go 1.21 or later installed +2. A text editor (VS Code recommended) +3. A terminal + +Verify your Go installation: + +```bash +go version +``` +``` + +Include it in every module: + +```markdown +# Module 3: Functions + +<include src="../../shared/setup.md"></include> + +## Functions in Go + +... +``` + +When you update the Go version requirement, you change `shared/setup.md` once and every module picks up the change on the next build. + +### Shared Code Examples + +If multiple modules reference the same helper code, put it in `shared/src/` and include it: + +```markdown +Here's the helper package we'll use throughout the course: + +<code src="../../shared/src/common/helpers.go"></code> +``` + +## Code Snippets for Focused Examples + +Sometimes you want to show only part of a file. Use snippets to highlight the relevant section: + +```go +// src/functions/main.go +package main + +import "fmt" + +// snippet: greet +func greet(name string) string { + return fmt.Sprintf("Hello, %s!", name) +} +// snippet: greet + +func main() { + message := greet("World") + fmt.Println(message) +} +``` + +Reference just the snippet: + +```markdown +Let's focus on the `greet` function: + +<code src="src/functions/main.go" snippet="greet"></code> +``` + +This renders only the `greet` function, not the full file. But the full file still compiles and runs, so the build validates that your snippet is part of working code. + +## Building the Master Document + +The top-level `hype.md` assembles all modules into a complete course: + +```markdown +# Go Programming Course + +<include src="modules/01-basics/hype.md"></include> + +<include src="modules/02-types/hype.md"></include> + +<include src="modules/03-functions/hype.md"></include> +``` + +Build the entire course as a single document: + +```bash +hype export -format html -f hype.md > course.html +``` + +Or build individual modules: + +```bash +hype export -format html -f modules/01-basics/hype.md > module-01.html +``` + +## Multiple Output Formats + +The same source produces different formats for different contexts: + +```bash +# HTML for web delivery +hype export -format html -f hype.md > course.html + +# Markdown for GitHub/GitLab rendering +hype export -format markdown -f hype.md > README.md + +# Individual modules for LMS upload +for module in modules/*/hype.md; do + name=$(basename $(dirname "$module")) + hype export -format html -f "$module" > "output/${name}.html" +done +``` + +## Keeping Materials Current + +Since all code is real and executed at build time, your CI pipeline catches problems before students do: + +```yaml +name: Validate Training Materials +on: [push, pull_request] + +jobs: + validate: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version-file: go.mod + - run: go install github.com/gopherguides/hype/cmd/hype@main + - run: hype export -format html -f hype.md > /dev/null +``` + +If any code example fails to compile, if any command produces unexpected output, or if any included file is missing, the build fails. You fix it before it reaches a classroom. + +## Real-World Example: Gopher Guides + +This isn't theoretical — [Gopher Guides](https://www.gopherguides.com) has been using this approach to build Go training materials for years. Hundreds of code examples across dozens of modules, all validated at build time, all using the include and snippet system described here. + +When Go 1.21 introduced the `log/slog` package, updating the logging module meant changing the source files and rebuilding. Every reference to the old examples was automatically updated. No grep-and-replace across Markdown files, no missed references, no stale screenshots. + +## Key Takeaways + +- **Code examples are real files** — the compiler validates them, not a human reviewer +- **Includes eliminate duplication** — shared content is written once and referenced everywhere +- **Snippets focus attention** — show only what matters while keeping the full file compilable +- **Build-time execution catches problems** — broken code fails the build, not the student +- **Multiple formats from one source** — HTML, Markdown, slides, all from the same content +- **CI integration** — automated validation on every push keeps materials current + +## Get Started + +```bash +brew install gopherguides/tap/hype + +mkdir training && cd training +mkdir -p modules/01-basics/src/hello +``` + +Create your first module, write a real Go example, include it in your document, and build. You'll have validated, executable training materials in minutes.