Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
32 changes: 32 additions & 0 deletions .github/workflows/quality.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Quality

on:
pull_request:
push:
branches:
- main

jobs:
quality:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v5

- name: Setup Node
uses: actions/setup-node@v6
with:
node-version: 24
cache: npm

- name: Install dependencies
run: npm ci

- name: Lint
run: npm run lint

- name: Check formatting
run: npm run format:check

- name: Run tests
run: npm test
2 changes: 2 additions & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/usr/bin/env sh
npx lint-staged
6 changes: 6 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
node_modules/
docs/.vitepress/dist/
.git-history-backup-20260519/
coverage/
artifacts/
temp/
20 changes: 13 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,19 @@ This repository is no longer only the `Learn Harness Engineering` course. It now
- a reusable VitePress course platform
- one active course selected at build time
- multiple course manifests under `courses/`
- isolated course content under `courses/<slug>/docs`

## Current structure

- active course selector: [docs/.vitepress/active-course.mjs](/Users/matheuspuppe/Desktop/estudo/course-builder/docs/.vitepress/active-course.mjs:1)
- active-course wrapper: [docs/.vitepress/course.manifest.mjs](/Users/matheuspuppe/Desktop/estudo/course-builder/docs/.vitepress/course.manifest.mjs:1)
- builder shell: [docs/.vitepress/config.mts](/Users/matheuspuppe/Desktop/estudo/course-builder/docs/.vitepress/config.mts:1)
- course manifests:
- [courses/learn-harness-engineering/course.manifest.mjs](/Users/matheuspuppe/Desktop/estudo/course-builder/courses/learn-harness-engineering/course.manifest.mjs:1)
- [courses/agent-ops-bootcamp/course.manifest.mjs](/Users/matheuspuppe/Desktop/estudo/course-builder/courses/agent-ops-bootcamp/course.manifest.mjs:1)
- course content roots:
- [courses/learn-harness-engineering/docs](/Users/matheuspuppe/Desktop/estudo/course-builder/courses/learn-harness-engineering/docs:1)
- [courses/agent-ops-bootcamp/docs](/Users/matheuspuppe/Desktop/estudo/course-builder/courses/agent-ops-bootcamp/docs:1)

## Commands

Expand All @@ -29,6 +34,7 @@ To inspect and switch courses:

```bash
npm run course:list
npm run course:new -- my-new-course "My New Course"
npm run course:activate -- learn-harness-engineering
npm run course:activate -- agent-ops-bootcamp
```
Expand All @@ -44,22 +50,22 @@ Each course manifest defines:
- `curriculum`
- `homeByLocale`

The VitePress layer reads the active manifest and builds nav, sidebar, branding, and homepage from it.
The VitePress layer reads the active manifest and points `srcDir` at that course's own `docs` directory. Nav, sidebar, branding, homepage, and markdown content all come from the active course.

## Creating a new course

1. Create `courses/<slug>/course.manifest.mjs`.
2. Start from one of the existing manifests.
3. Define the course `site`, `brand`, `theme`, `locales`, `curriculum`, and `homeByLocale`.
4. Switch to it with `npm run course:activate -- <slug>`.
5. Update `docs/` markdown content so it matches the new curriculum.
2. Or scaffold both manifesto and docs with `npm run course:new -- <slug> "Course Title"`.
3. Create `courses/<slug>/docs/` if you did not use the scaffold command.
4. Define the course `site`, `brand`, `theme`, `locales`, `curriculum`, and `homeByLocale`.
5. Add markdown content under `courses/<slug>/docs/<locale>/...` to match the curriculum.
6. Switch to it with `npm run course:activate -- <slug>`.

## Current limitations

- only one course is active per build
- `docs/` content is still mostly from `Learn Harness Engineering`
- the current manifest format is code-first, not CMS-driven
- the public docs URLs still depend on each course's configured `site.base`
- only one course is active per build

## Validation

Expand Down
15 changes: 9 additions & 6 deletions WHITELABEL.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ O projeto agora está estruturado para suportar múltiplos cursos com um curso a

- curso ativo: [docs/.vitepress/active-course.mjs](/Users/matheuspuppe/Desktop/estudo/course-builder/docs/.vitepress/active-course.mjs:1)
- manifesto do curso atual: [courses/learn-harness-engineering/course.manifest.mjs](/Users/matheuspuppe/Desktop/estudo/course-builder/courses/learn-harness-engineering/course.manifest.mjs:1)
- conteúdo do curso atual: [courses/learn-harness-engineering/docs](/Users/matheuspuppe/Desktop/estudo/course-builder/courses/learn-harness-engineering/docs:1)
- wrappers compatíveis com a camada antiga:
- [docs/.vitepress/course.config.mjs](/Users/matheuspuppe/Desktop/estudo/course-builder/docs/.vitepress/course.config.mjs:1)
- [docs/.vitepress/course-content.mjs](/Users/matheuspuppe/Desktop/estudo/course-builder/docs/.vitepress/course-content.mjs:1)
Expand All @@ -19,13 +20,15 @@ O projeto agora está estruturado para suportar múltiplos cursos com um curso a
- manifesto de locales e labels de UI
- currículo por locale
- conteúdo da homepage por locale
- conteúdo markdown por curso
- seleção do curso ativo

## Como criar outro curso

1. Crie uma pasta `courses/<slug>/`.
2. Copie [courses/learn-harness-engineering/course.manifest.mjs](/Users/matheuspuppe/Desktop/estudo/course-builder/courses/learn-harness-engineering/course.manifest.mjs:1) para o novo slug.
3. Edite no manifesto:
2. Crie `courses/<slug>/docs/`.
3. Copie [courses/learn-harness-engineering/course.manifest.mjs](/Users/matheuspuppe/Desktop/estudo/course-builder/courses/learn-harness-engineering/course.manifest.mjs:1) para o novo slug.
4. Edite no manifesto:
- `site.title`
- `site.description`
- `site.base`
Expand All @@ -35,17 +38,17 @@ O projeto agora está estruturado para suportar múltiplos cursos com um curso a
- `locales`
- `curriculum`
- `homeByLocale`
4. Aponte [docs/.vitepress/active-course.mjs](/Users/matheuspuppe/Desktop/estudo/course-builder/docs/.vitepress/active-course.mjs:1) para o novo manifesto.
5. Reescreva o conteúdo real em `docs/<locale>/` para bater com o currículo do novo curso.
5. Adicione o conteúdo real em `courses/<slug>/docs/<locale>/` para bater com o currículo do novo curso.
6. Ative o curso.

Ou use os comandos:

- `npm run course:list`
- `npm run course:new -- <slug> "Course Title"`
- `npm run course:activate -- <slug>`

## Limitações atuais

- o conteúdo markdown em `docs/` ainda é do curso `Learn Harness Engineering`
- o manifesto do curso atual ainda concentra muito conteúdo inline
- ainda existe apenas um curso ativo por build
- `README.md` ainda descreve o curso atual, não a plataforma
- o builder ainda depende de manifests em código, não de uma camada editorial
88 changes: 47 additions & 41 deletions courses/agent-ops-bootcamp/course.manifest.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,30 @@ const courseManifest = {
description:
"A compact course on operating, debugging, and shipping agentic workflows in production teams.",
base: "/course-builder/",
repoTreeUrl: "https://github.com/puppe1990/course-builder/tree/main"
repoTreeUrl: "https://github.com/puppe1990/course-builder/tree/main",
},
brand: {
logo:
'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%230B6E4F" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 12h16"/><path d="M12 4v16"/><circle cx="12" cy="12" r="8"/></svg>'
logo: 'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%230B6E4F" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 12h16"/><path d="M12 4v16"/><circle cx="12" cy="12" r="8"/></svg>',
},
theme: {
fontStylesheets: [
"https://fonts.googleapis.com/css2?family=Newsreader:opsz,wght@6..72,400;6..72,600&family=Plus+Jakarta+Sans:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap"
"https://fonts.googleapis.com/css2?family=Newsreader:opsz,wght@6..72,400;6..72,600&family=Plus+Jakarta+Sans:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap",
],
typography: {
body:
"'Plus Jakarta Sans', ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
body: "'Plus Jakarta Sans', ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
heading:
"'Newsreader', ui-serif, Georgia, Cambria, 'Times New Roman', Times, serif",
mono:
"'JetBrains Mono', 'Fira Code', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace",
mermaid: "'Plus Jakarta Sans', sans-serif"
mono: "'JetBrains Mono', 'Fira Code', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace",
mermaid: "'Plus Jakarta Sans', sans-serif",
},
layout: {
maxWidth: "1280px",
sidebarWidth: "280px",
cardRadius: "14px"
cardRadius: "14px",
},
effects: {
featureShadow: "0 18px 48px rgba(11, 110, 79, 0.14)",
featureShadowDark: "0 18px 48px rgba(0, 0, 0, 0.4)"
featureShadowDark: "0 18px 48px rgba(0, 0, 0, 0.4)",
},
colors: {
light: {
Expand All @@ -47,7 +44,7 @@ const courseManifest = {
brandSoft: "rgba(11, 110, 79, 0.12)",
divider: "rgba(8, 32, 20, 0.1)",
sidebarBg: "#ECF5F0",
navBg: "#F6FBF8"
navBg: "#F6FBF8",
},
dark: {
bg: "#0E1712",
Expand All @@ -63,9 +60,9 @@ const courseManifest = {
brandSoft: "rgba(57, 163, 127, 0.16)",
divider: "rgba(255, 255, 255, 0.12)",
sidebarBg: "#0A120D",
navBg: "#0E1712"
}
}
navBg: "#0E1712",
},
},
},
locales: [
{
Expand All @@ -78,71 +75,80 @@ const courseManifest = {
resources: "Toolkit",
skills: "Playbooks",
resourceLibrary: "Toolkit",
tryHarness: "Open Templates ↗"
}
}
tryHarness: "Open Templates ↗",
},
},
],
curriculum: {
en: {
lectures: [
{ text: "Welcome", link: "/en/" },
{ text: "Operate Agents with Guardrails", link: "/en/lectures/operate-agents-with-guardrails/" },
{ text: "Debug Long-Running Workflows", link: "/en/lectures/debug-long-running-workflows/" },
{ text: "Ship with Runtime Feedback", link: "/en/lectures/ship-with-runtime-feedback/" }
{
text: "Operate Agents with Guardrails",
link: "/en/lectures/operate-agents-with-guardrails/",
},
{
text: "Debug Long-Running Workflows",
link: "/en/lectures/debug-long-running-workflows/",
},
{
text: "Ship with Runtime Feedback",
link: "/en/lectures/ship-with-runtime-feedback/",
},
],
projects: [
{ text: "Overview", link: "/en/projects/" },
{ text: "Incident Drill", link: "/en/projects/incident-drill/" },
{ text: "Release Checklist", link: "/en/projects/release-checklist/" }
{ text: "Release Checklist", link: "/en/projects/release-checklist/" },
],
resources: [
{ text: "Overview", link: "/en/resources/" },
{ text: "Runbooks", link: "/en/resources/templates/" },
{ text: "Reference", link: "/en/resources/reference/" },
{ text: "Advanced Ops", link: "/en/resources/openai-advanced/" }
{ text: "Advanced Ops", link: "/en/resources/openai-advanced/" },
],
skills: [{ text: "Playbooks", link: "/en/skills/" }]
}
skills: [{ text: "Playbooks", link: "/en/skills/" }],
},
},
homeByLocale: {
en: {
hero: {
title: "Welcome to Agent Ops Bootcamp",
intro: [
"Agent Ops Bootcamp focuses on how teams run, observe, and correct agentic systems under production constraints.",
"The course is intentionally compact: a few modules, a few labs, and a toolkit you can adapt to your own operating model."
"The course is intentionally compact: a few modules, a few labs, and a toolkit you can adapt to your own operating model.",
],
references: [
{
label: "Operational feedback loops",
href: "https://openai.com/index/harness-engineering/"
}
]
href: "https://openai.com/index/harness-engineering/",
},
],
},
sections: {
start: "Start here",
mechanism: "Operating loop",
learn: "You will practice",
next: "Next moves"
next: "Next moves",
},
startText:
"This sample course exists to prove the platform can host a second curriculum with different naming, visual identity, and positioning.",
cards: [
{
title: "Modules",
body: "Short theory units about operating agents safely.",
href: "./lectures/operate-agents-with-guardrails/"
href: "./lectures/operate-agents-with-guardrails/",
},
{
title: "Labs",
body: "Hands-on operational drills.",
href: "./projects/"
href: "./projects/",
},
{
title: "Toolkit",
body: "Runbooks and reusable templates.",
href: "./resources/"
}
href: "./resources/",
},
],
mechanismText:
"Production agent work improves when runtime feedback and verification are part of the operating loop.",
Expand All @@ -155,23 +161,23 @@ const courseManifest = {
learnItems: [
"Define operator-facing guardrails.",
"Treat logs and runtime feedback as first-class inputs.",
"Run lightweight drills before real incidents."
"Run lightweight drills before real incidents.",
],
nextIntro: "The sample path is intentionally small:",
nextSteps: [
{
title: "Module 1",
description: "Start with guardrails.",
href: "./lectures/operate-agents-with-guardrails/"
href: "./lectures/operate-agents-with-guardrails/",
},
{
title: "Lab 1",
description: "Run an incident drill.",
href: "./projects/incident-drill/"
}
]
}
}
href: "./projects/incident-drill/",
},
],
},
},
};

export default courseManifest;
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Debug Long-Running Workflows

Long-running agents rarely fail in one obvious place. They drift, loop, or lose context across steps.

## What to inspect

- Execution logs
- State transitions
- Retry behavior
- Handoff boundaries

## Debugging principle

Treat every long-running workflow as an observable system, not a black box prompt.
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Operate Agents with Guardrails

Agent systems need explicit operating boundaries. This module shows how teams define ownership, stop conditions, and escalation paths before runtime issues become incidents.

## Core rules

- Define who can trigger the workflow.
- Define what the agent can change without approval.
- Define when the system must pause and ask for human review.

## Outcome

By the end of this module, you should have a lightweight guardrail policy that can be attached to any agent workflow.
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Ship with Runtime Feedback

Shipping agent systems safely requires a feedback loop between runtime behavior and product decisions.

## Runtime inputs

- Error classes
- Human overrides
- Repeated retries
- Failed postconditions

## Practice

Turn the most common runtime failures into explicit operating rules and release checks.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Incident Drill

Simulate a production issue where an agent keeps retrying a task with stale context.

## Deliverable

Write the operator checklist your team should follow in the first ten minutes of the incident.
3 changes: 3 additions & 0 deletions courses/agent-ops-bootcamp/docs/en/projects/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Labs

Use these labs to pressure-test your operating model before a real release.
Loading