Context. I'm wiring docgen into the courseforge/infrastructure suite as a Tekton Task (smoke landed in deploy/kubernetes/tekton-dag/base/docgen-task.yaml — uses docgen init today as a no-dep wiring smoke). The medium-term plan is to drive docgen from course-builder's annotated Playwright tests so each documented function gets a short, single-purpose video that demonstrates exactly one behavior — the same way a Playwright test('…') describes one scenario.
The full design lives in docs/per-function-video-docs.md (the file you're reading from inside this repo, or the rendered version on courseforge.github.io once published).
PoC results that informed this ask (2026-05-03). I drove today's docgen playwright against a course-builder-shaped stub on a Cloud Agent VM. End-to-end run worked (~100 KB recording produced in ~5 s), but it surfaced five concrete sharp edges that docgen demo-function should smooth out — full write-up in docs/per-function-video-docs.md § PoC. The asks below are the asks those findings translate into.
Ask. Add a new CLI subcommand:
docgen demo-function \
--manifest <path-to-test-or-yaml> \
--output <out-dir>
that:
- Reads one manifest entry matching the contract documented in
per-function-video-docs.md § Contract. Two acceptable input shapes: (a) a Playwright spec file with a { type: "docgen", description: <JSON-encoded contract> } annotation, (b) a sibling *.docgen.yaml. Either is fine; pick whichever is easiest to support first and document the other as TODO.
- Runs the referenced demonstration:
kind: playwright → reuse the existing docgen playwright plumbing, but driven by --grep "<test_name>" against the spec file, against a dev server URL passed in (or auto-detected from playwright.config.ts).
kind: cli → reuse the existing docgen vhs plumbing against the referenced .tape.
- Renders narration from the contract's
intent field via the existing TTS path (no new TTS code).
- Composes one short MP4 (target 15–60 s, single segment, no
docgen concat) plus:
- a poster frame (PNG, last frame of the demo by default),
- a stable URL fragment of the form
#fn-{repo-slug}-{symbol} so consumer docs can deep-link.
- Surfaces the contract's
assertions_to_surface lines as on-screen highlights / closing caption (whatever your existing overlay system supports — visual treatment is your call).
Concrete asks the PoC turned up (each maps to a finding in the PoC section linked above):
- (F1) Either accept
.webm recordings as a first-class output format, or transcode to .mp4 via the existing ffmpeg runtime dep before validating the output path. Today, playwright_runner.PlaywrightRunner.capture() just checks output_path.exists() against an .mp4 filename, so users have to shutil.copy .webm bytes to the .mp4 path to make the validator happy.
- (F2) Take a Playwright test +
--grep "<test_name>" filter as input, not a Python capture script that has to read DOCGEN_PLAYWRIGHT_OUTPUT / _URL from env. Run the test under your own recording context internally. This is what makes the contract author's life easy: they write a normal Playwright test, you record it.
- (F3) Default the recording viewport from the manifest entry's
output_budget.resolution, not from docgen.yaml's playwright.default_viewport. Today the env-var contract leaks the resolution decision to the script.
- (F5) Accept either the Node
@playwright/test annotation shape or a Python pytest.mark.docgen(...) marker (course-builder uses pytest + playwright.sync_api, so the Node-only shape excludes it). A sibling *.docgen.yaml lookup keyed by {file, test_name} is also fine for non-Playwright projects.
Asks discovered while building the Round-2 shim (newly recorded in docs/per-function-video-docs.md § Round 2 → new findings):
- (F6) Use Playwright's native locator API (
page.locator(sel).filter(has_text=text).first.wait_for(...)) when waiting on text — page.wait_for_function JS predicates break when the selector contains ", and the obvious json.dumps-the-selector workaround interacts badly with Python triple-quoted strings.
- (F7) Implement marker discovery via
ast.parse + decorator walking, not a regex over the source. A regex matches text inside module docstrings that talk about the marker (e.g. doc comments saying "the @pytest.mark.docgen(...) decorator below").
A working reference implementation lives at tools/docgen-shim/demo_function.py — feel free to crib from it. Total ~400 lines, MIT-licensed (matches documentation-generator's own license per pyproject.toml).
Caching. Re-renders should be skipped when the cache key documented in per-function-video-docs.md § Caching (sha256(fn_source_sha + intent_sha + fixture_sha)) matches a previous run. Existing docgen cache infra is fine; just key it on those three SHAs instead of the project-level segment IDs.
Out of scope (please do not implement here). Hosting / CDN choices for the MP4s, S3 layout, GitHub Pages publishing of per-function videos. Those land in the suite's Tekton orchestration Task (courseforge/infrastructure) once the upstream subcommand exists. This issue is about the CLI surface.
Why this is upstream and not a fork. The whole reason documentation-generator is a separate project is that the rendering pipeline (TTS → Manim → VHS → ffmpeg → validate → concat → pages) is the hard part and we do not want a second implementation. Adding demo-function upstream means every consumer (course-builder is the first; others will follow) gets the same shape. We orchestrate from courseforge/infrastructure; the implementation belongs to you.
Happy to PR a draft once the shape is agreed. Open to bikeshedding the subcommand name (demo-function is a working title; per-function, func, case all work).
Tracked from courseforge/infrastructure — per-function-video-docs.md § Upstream issue draft.
Context. I'm wiring
docgeninto thecourseforge/infrastructuresuite as a TektonTask(smoke landed indeploy/kubernetes/tekton-dag/base/docgen-task.yaml— usesdocgen inittoday as a no-dep wiring smoke). The medium-term plan is to drivedocgenfrom course-builder's annotated Playwright tests so each documented function gets a short, single-purpose video that demonstrates exactly one behavior — the same way a Playwrighttest('…')describes one scenario.The full design lives in
docs/per-function-video-docs.md(the file you're reading from inside this repo, or the rendered version oncourseforge.github.ioonce published).PoC results that informed this ask (2026-05-03). I drove today's
docgen playwrightagainst a course-builder-shaped stub on a Cloud Agent VM. End-to-end run worked (~100 KB recording produced in ~5 s), but it surfaced five concrete sharp edges thatdocgen demo-functionshould smooth out — full write-up indocs/per-function-video-docs.md§ PoC. The asks below are the asks those findings translate into.Ask. Add a new CLI subcommand:
that:
per-function-video-docs.md§ Contract. Two acceptable input shapes: (a) a Playwright spec file with a{ type: "docgen", description: <JSON-encoded contract> }annotation, (b) a sibling*.docgen.yaml. Either is fine; pick whichever is easiest to support first and document the other as TODO.kind: playwright→ reuse the existingdocgen playwrightplumbing, but driven by--grep "<test_name>"against the spec file, against a dev server URL passed in (or auto-detected fromplaywright.config.ts).kind: cli→ reuse the existingdocgen vhsplumbing against the referenced.tape.intentfield via the existing TTS path (no new TTS code).docgen concat) plus:#fn-{repo-slug}-{symbol}so consumer docs can deep-link.assertions_to_surfacelines as on-screen highlights / closing caption (whatever your existing overlay system supports — visual treatment is your call).Concrete asks the PoC turned up (each maps to a finding in the PoC section linked above):
.webmrecordings as a first-class output format, or transcode to.mp4via the existingffmpegruntime dep before validating the output path. Today,playwright_runner.PlaywrightRunner.capture()just checksoutput_path.exists()against an.mp4filename, so users have toshutil.copy.webmbytes to the.mp4path to make the validator happy.--grep "<test_name>"filter as input, not a Python capture script that has to readDOCGEN_PLAYWRIGHT_OUTPUT/_URLfrom env. Run the test under your own recording context internally. This is what makes the contract author's life easy: they write a normal Playwright test, you record it.output_budget.resolution, not fromdocgen.yaml'splaywright.default_viewport. Today the env-var contract leaks the resolution decision to the script.@playwright/testannotationshape or a Pythonpytest.mark.docgen(...)marker (course-builder usespytest+playwright.sync_api, so the Node-only shape excludes it). A sibling*.docgen.yamllookup keyed by{file, test_name}is also fine for non-Playwright projects.Asks discovered while building the Round-2 shim (newly recorded in
docs/per-function-video-docs.md§ Round 2 → new findings):page.locator(sel).filter(has_text=text).first.wait_for(...)) when waiting on text —page.wait_for_functionJS predicates break when the selector contains", and the obviousjson.dumps-the-selector workaround interacts badly with Python triple-quoted strings.ast.parse+ decorator walking, not a regex over the source. A regex matches text inside module docstrings that talk about the marker (e.g. doc comments saying "the@pytest.mark.docgen(...)decorator below").A working reference implementation lives at
tools/docgen-shim/demo_function.py— feel free to crib from it. Total ~400 lines, MIT-licensed (matchesdocumentation-generator's own license perpyproject.toml).Caching. Re-renders should be skipped when the cache key documented in
per-function-video-docs.md§ Caching (sha256(fn_source_sha + intent_sha + fixture_sha)) matches a previous run. Existingdocgencache infra is fine; just key it on those three SHAs instead of the project-level segment IDs.Out of scope (please do not implement here). Hosting / CDN choices for the MP4s, S3 layout, GitHub Pages publishing of per-function videos. Those land in the suite's Tekton orchestration Task (
courseforge/infrastructure) once the upstream subcommand exists. This issue is about the CLI surface.Why this is upstream and not a fork. The whole reason
documentation-generatoris a separate project is that the rendering pipeline (TTS → Manim → VHS → ffmpeg → validate → concat → pages) is the hard part and we do not want a second implementation. Addingdemo-functionupstream means every consumer (course-builder is the first; others will follow) gets the same shape. We orchestrate fromcourseforge/infrastructure; the implementation belongs to you.Happy to PR a draft once the shape is agreed. Open to bikeshedding the subcommand name (
demo-functionis a working title;per-function,func,caseall work).Tracked from
courseforge/infrastructure—per-function-video-docs.md§ Upstream issue draft.