From 8184dbac0c0db5d3cc1c9012738d9df45c315539 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 30 Jul 2026 11:00:09 +0000
Subject: [PATCH 1/2] Implement code snippet wrapping
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
scripts/build-docs.test.js | 30 +++++++++++++++++++++++++
scripts/lib/docs.css | 45 +++++++++++++++++++++++++++++++++++++
scripts/lib/marked-setup.js | 42 +++++++++++++++++++++++++++++-----
3 files changed, 112 insertions(+), 5 deletions(-)
diff --git a/scripts/build-docs.test.js b/scripts/build-docs.test.js
index d389bbf7..e8f367af 100644
--- a/scripts/build-docs.test.js
+++ b/scripts/build-docs.test.js
@@ -22,6 +22,22 @@ function buildDocs() {
};
}
+function renderSnippet(markdown) {
+ return execFileSync(
+ process.execPath,
+ [
+ "-e",
+ `
+ const { marked } = require("marked");
+ const { setupBasePlugins } = require("./scripts/lib/marked-setup");
+ setupBasePlugins();
+ process.stdout.write(marked.parse(${JSON.stringify(markdown)}));
+ `,
+ ],
+ { cwd: repoDir, encoding: "utf8" }
+ );
+}
+
test("workshop SPA renders a single document h1", () => {
const { html } = buildDocs();
@@ -103,6 +119,20 @@ test("markdown, md, yaml, and yml code blocks use compact icon-only editor chrom
assert.ok(css.includes("padding: 12px;"), "expected compact YAML code padding");
});
+test("code blocks wrap long lines without relying on mobile-only styles", () => {
+ const { css } = buildDocs();
+
+ assert.ok(css.includes(".markdown-body pre {\n position: relative;\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n}"));
+ assert.ok(css.includes(".markdown-body pre > code {\n font-size: 1em;\n white-space: inherit;\n}"));
+});
+
+test("code block headers can render filenames from fence metadata", () => {
+ const html = renderSnippet("```yaml .github/workflows/hello.yml\nname: Hello\n```\n\n```markdown title=\"README.md\"\n# Hello\n```");
+
+ assert.ok(html.includes('.github/workflows/hello.yml'));
+ assert.ok(html.includes('README.md'));
+});
+
test("rendered workshop images use GitHub-like rounded corners", () => {
const { css } = buildDocs();
diff --git a/scripts/lib/docs.css b/scripts/lib/docs.css
index d5ab6f9c..0fe055b2 100644
--- a/scripts/lib/docs.css
+++ b/scripts/lib/docs.css
@@ -550,9 +550,12 @@ html[data-color-mode="dark"] .workshop-nav-btn-secondary:focus-visible {
/* Code block copy button */
.markdown-body pre {
position: relative;
+ white-space: pre-wrap;
+ overflow-wrap: anywhere;
}
.markdown-body pre > code {
font-size: 1em;
+ white-space: inherit;
}
.code-copy-btn {
position: absolute;
@@ -616,6 +619,7 @@ html[data-color-mode="dark"] .code-copy-btn:hover {
display: flex;
align-items: center;
gap: 6px;
+ min-width: 0;
padding: 8px 14px;
background-color: #161b22;
border-bottom: 1px solid #30363d;
@@ -639,6 +643,20 @@ html[data-color-mode="dark"] .code-copy-btn:hover {
font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
}
+.code-block-filename {
+ min-width: 0;
+ margin-left: auto;
+ overflow: hidden;
+ font-size: 11px;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.terminal-bar .code-block-filename {
+ color: #8b949e;
+ font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
+}
+
.markdown-body .terminal-pre {
margin: 0;
padding: 16px;
@@ -681,6 +699,7 @@ html[data-color-mode="dark"] .code-copy-btn:hover {
display: flex;
align-items: center;
gap: 8px;
+ min-width: 0;
padding: 8px 14px;
background: linear-gradient(90deg, #271052, #3b1b6f);
border-bottom: 1px solid #8957e5;
@@ -706,6 +725,10 @@ html[data-color-mode="dark"] .code-copy-btn:hover {
letter-spacing: 0.02em;
}
+.agent-prompt-bar .code-block-filename {
+ color: #c6a7ff;
+}
+
.markdown-body .agent-prompt-pre {
margin: 0;
padding: 16px 16px 16px 20px;
@@ -952,6 +975,7 @@ html[data-color-mode="dark"] .markdown-body li.task-list-item:not(.is-static).is
display: flex;
align-items: center;
gap: 8px;
+ min-width: 0;
padding: 8px 14px;
background-color: var(--bgColor-muted, #f6f8fa);
border-bottom: 1px solid var(--borderColor-muted, #d0d7de);
@@ -964,6 +988,10 @@ html[data-color-mode="dark"] .markdown-body li.task-list-item:not(.is-static).is
line-height: 1;
}
+.markdown-editor-bar .code-block-filename {
+ color: var(--fgColor-muted, #59636e);
+}
+
.markdown-body .markdown-editor-pre {
margin: 0;
padding: 12px 12px 12px 16px;
@@ -1004,6 +1032,9 @@ html[data-color-mode="dark"] .markdown-body li.task-list-item:not(.is-static).is
html[data-color-mode="auto"] .markdown-editor-icon {
color: #8b949e;
}
+ html[data-color-mode="auto"] .markdown-editor-bar .code-block-filename {
+ color: #8b949e;
+ }
html[data-color-mode="auto"] .markdown-body .markdown-editor-pre {
background-color: #0d1117;
box-shadow: inset 3px 0 #30363d;
@@ -1032,6 +1063,9 @@ html[data-color-mode="dark"] .markdown-editor-bar {
html[data-color-mode="dark"] .markdown-editor-icon {
color: #8b949e;
}
+html[data-color-mode="dark"] .markdown-editor-bar .code-block-filename {
+ color: #8b949e;
+}
html[data-color-mode="dark"] .markdown-body .markdown-editor-pre {
background-color: #0d1117;
box-shadow: inset 3px 0 #30363d;
@@ -1061,6 +1095,7 @@ html[data-color-mode="dark"] .markdown-editor-block .code-copy-btn:hover {
display: flex;
align-items: center;
gap: 8px;
+ min-width: 0;
padding: 8px 14px;
background-color: var(--bgColor-muted, #f6f8fa);
border-bottom: 1px solid var(--borderColor-muted, #d0d7de);
@@ -1073,6 +1108,10 @@ html[data-color-mode="dark"] .markdown-editor-block .code-copy-btn:hover {
line-height: 1;
}
+.yaml-editor-bar .code-block-filename {
+ color: var(--fgColor-muted, #59636e);
+}
+
.markdown-body .yaml-editor-pre {
margin: 0;
padding: 12px;
@@ -1112,6 +1151,9 @@ html[data-color-mode="dark"] .markdown-editor-block .code-copy-btn:hover {
html[data-color-mode="auto"] .yaml-editor-icon {
color: #8b949e;
}
+ html[data-color-mode="auto"] .yaml-editor-bar .code-block-filename {
+ color: #8b949e;
+ }
html[data-color-mode="auto"] .markdown-body .yaml-editor-pre {
background-color: #0d1117;
}
@@ -1139,6 +1181,9 @@ html[data-color-mode="dark"] .yaml-editor-bar {
html[data-color-mode="dark"] .yaml-editor-icon {
color: #8b949e;
}
+html[data-color-mode="dark"] .yaml-editor-bar .code-block-filename {
+ color: #8b949e;
+}
html[data-color-mode="dark"] .markdown-body .yaml-editor-pre {
background-color: #0d1117;
}
diff --git a/scripts/lib/marked-setup.js b/scripts/lib/marked-setup.js
index 208fa403..cda56227 100644
--- a/scripts/lib/marked-setup.js
+++ b/scripts/lib/marked-setup.js
@@ -19,6 +19,34 @@ const slugger = new GithubSlugger();
const shellLangs = new Set(['bash', 'sh', 'shell', 'zsh']);
const terminalOutputLangs = new Set(['console', 'output', 'plaintext', 'text']);
+function extractCodeBlockFilename(meta = '') {
+ let normalizedMeta = meta.trim();
+ if (!normalizedMeta) return '';
+
+ if (normalizedMeta.startsWith('{') && normalizedMeta.endsWith('}')) {
+ normalizedMeta = normalizedMeta.slice(1, -1).trim();
+ }
+
+ const keyedFilenameMatch = normalizedMeta.match(
+ /(?:^|\s)(?:file|filename|path|title)=(?:"([^"]+)"|'([^']+)'|(\S+))/
+ );
+ if (keyedFilenameMatch) {
+ return keyedFilenameMatch[1] || keyedFilenameMatch[2] || keyedFilenameMatch[3] || '';
+ }
+
+ return /\s|=/.test(normalizedMeta) ? '' : normalizedMeta;
+}
+
+function parseCodeBlockInfo(lang = '') {
+ const info = lang.trim();
+ const firstTokenMatch = info.match(/^\S*/);
+ const langKey = (firstTokenMatch?.[0] || '').toLowerCase();
+ const meta = info.slice(firstTokenMatch?.[0]?.length || 0).trim();
+ const filename = extractCodeBlockFilename(meta);
+
+ return { langKey, filename };
+}
+
// Register the heading anchor, task-list item, alert, syntax-highlight, and
// code-block renderer plugins. Call this once before processing any markdown.
function setupBasePlugins() {
@@ -88,22 +116,26 @@ function setupBasePlugins() {
useNewRenderer: true,
renderer: {
code({ text, lang, escaped }) {
- const langKey = (lang || '').match(/^\S*/)?.[0]?.toLowerCase() ?? '';
+ const { langKey, filename } = parseCodeBlockInfo(lang || '');
const codeText = text.replace(/\n$/, '') + '\n';
const codeHtml = escaped ? codeText : escapeHtml(codeText);
+ const filenameHtml = filename
+ ? `${escapeHtml(filename)}`
+ : '';
if (langKey === 'prompt') {
- return `
\n
✦Agent prompt
\n
${codeHtml}
\n
\n`;
+ return `\n
✦Agent prompt${filenameHtml}
\n
${codeHtml}
\n
\n`;
}
if (langKey === 'markdown' || langKey === 'md') {
- return `\n`;
+ return `\n
◇${filenameHtml}
\n
${codeHtml}
\n
\n`;
}
if (langKey === 'yaml' || langKey === 'yml') {
- return `\n`;
+ return `\n
≡${filenameHtml}
\n
${codeHtml}
\n
\n`;
}
const terminalLabel = shellLangs.has(langKey) ? langKey : terminalOutputLangs.has(langKey) ? 'output' : '';
if (!terminalLabel) return false;
const escapedLang = escapeHtml(langKey);
- return `\n
${terminalLabel}
\n
${codeHtml}
\n
\n`;
+ const terminalBarAria = filename ? '' : ' aria-hidden="true"';
+ return `\n
${terminalLabel}${filenameHtml}
\n
${codeHtml}
\n
\n`;
},
},
});
From 85b434214e88008e17116246a91e2c1df1b8bfcd Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 30 Jul 2026 11:10:18 +0000
Subject: [PATCH 2/2] docs: document snippet filenames
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
.github/workflows/guidelines.md | 3 +++
workshop/04-github-actions-intro.md | 7 +++----
workshop/07-your-first-workflow.md | 2 +-
workshop/07d-confirm-model-access.md | 2 +-
workshop/14b-pr-reviewer-workflow.md | 4 ++--
workshop/15-conditional-logic.md | 6 +++---
workshop/16-connect-data-source.md | 6 +++---
workshop/17-add-mcp-tools.md | 4 ++--
workshop/18-share-and-reuse.md | 2 +-
workshop/19-research-driven-training-node.md | 2 +-
workshop/20-persistent-memory.md | 4 ++--
workshop/21-inline-sub-agents.md | 4 ++--
workshop/22-error-handling-and-resilience.md | 6 +++---
workshop/23-ab-experiments.md | 8 ++++----
workshop/24-self-hosted-runners.md | 6 +++---
workshop/26-manage-costs-and-budgets.md | 2 +-
workshop/27-evaluate-workflow-quality.md | 2 +-
17 files changed, 36 insertions(+), 34 deletions(-)
diff --git a/.github/workflows/guidelines.md b/.github/workflows/guidelines.md
index f827acfe..db8bbf95 100644
--- a/.github/workflows/guidelines.md
+++ b/.github/workflows/guidelines.md
@@ -229,6 +229,9 @@ Multi-line callout (summary + body):
- Use ` ```text ` for terminal output that learners read but do not type (for example, expected command output or error messages).
- Use ` ```yaml ` for standalone YAML configuration fragments, ` ```markdown ` for Markdown syntax examples, and ` ```html ` or ` ```xml ` for markup.
- When showing an agentic workflow example that includes both frontmatter and prompt body, prefer a ` ```markdown ` block that shows the full Markdown+frontmatter file shape instead of isolating the frontmatter in a standalone ` ```yaml ` region.
+- When a fenced snippet represents the contents of a file, add the filename after the language token so the rendered snippet chrome can surface it (for example, ` ```markdown .github/workflows/daily-status.md ` or ` ```yaml .github/workflows/daily-status.lock.yml `).
+- Prefer the bare relative path form for filename metadata in workshop content. The renderer also supports keyed metadata such as `title=` or `file=`, but workshop pages should use the bare path consistently unless a page needs a more complex title.
+- Match the filename extension to the snippet language (`.md` for `markdown`, `.yml`/`.yaml` for `yaml`, and so on), and keep the same filename across a page while the learner is still editing that same file.
## Enterprise user preference in design decisions
diff --git a/workshop/04-github-actions-intro.md b/workshop/04-github-actions-intro.md
index 275cfaea..90e50ac6 100644
--- a/workshop/04-github-actions-intro.md
+++ b/workshop/04-github-actions-intro.md
@@ -39,7 +39,7 @@ A GitHub Actions workflow is a YAML file in `.github/workflows/` that tells GitH
Annotated example — each comment names the key term (this is a standard Actions workflow, not an agentic workflow):
-```yaml
+```yaml .github/workflows/hello-workflow.yml
# Standard GitHub Actions workflow — not an agentic workflow
name: Hello Workflow
@@ -57,7 +57,7 @@ jobs:
A **runner** is the machine GitHub provisions for each job — fresh and isolated for every run.
-```markdown
+```markdown .github/workflows/hello-workflow.md
---
runs-on: ubuntu-latest # also: windows-latest, macos-latest
---
@@ -84,7 +84,7 @@ The diagram below shows how the five key parts fit together in every workflow fi
Before reading on, label each highlighted part of the workflow below with its type:
`trigger`, `job`, `runner`, `step`, or `action`.
-```yaml
+```yaml .github/workflows/hello-workflow.yml
on: [push]
jobs:
test:
@@ -137,4 +137,3 @@ Open a real workflow file and find the three core building blocks — no termina
**Next:** [What Are Agentic Workflows?](05-agentic-workflows-intro.md)
-
diff --git a/workshop/07-your-first-workflow.md b/workshop/07-your-first-workflow.md
index 0f94368b..ab647d67 100644
--- a/workshop/07-your-first-workflow.md
+++ b/workshop/07-your-first-workflow.md
@@ -62,7 +62,7 @@ Review the agent's edit, then continue. Prefer this path over hand-editing each
**What the agent created** — the generated file should look roughly like this:
-```markdown
+```markdown .github/workflows/daily-report-status.md
---
name: Daily Report Status
on:
diff --git a/workshop/07d-confirm-model-access.md b/workshop/07d-confirm-model-access.md
index 8cb45439..c4178e38 100644
--- a/workshop/07d-confirm-model-access.md
+++ b/workshop/07d-confirm-model-access.md
@@ -96,7 +96,7 @@ Use this path when the organization that owns the repository has centralized Cop
1. Ask your organization administrator to confirm centralized billing is enabled.
2. Open `daily-report-status.md` and confirm the `permissions:` block includes `copilot-requests: write`:
-```markdown
+```markdown .github/workflows/daily-report-status.md
---
permissions:
contents: read
diff --git a/workshop/14b-pr-reviewer-workflow.md b/workshop/14b-pr-reviewer-workflow.md
index 02d33096..2f55b701 100644
--- a/workshop/14b-pr-reviewer-workflow.md
+++ b/workshop/14b-pr-reviewer-workflow.md
@@ -48,7 +48,7 @@ Review the agent's diff before accepting it. The source should contain one paren
The workflow frontmatter should follow this shape:
-```markdown
+```markdown .github/workflows/pr-reviewer.md
---
on:
pull_request:
@@ -76,7 +76,7 @@ Notice that the agent job has no repository or pull request write permission. `c
Near the bottom, look for the two reusable blocks:
-```markdown
+```markdown .github/workflows/pr-reviewer.md
## agent: `pr-reviewer`
---
description: Reviews one pull request for actionable problems
diff --git a/workshop/15-conditional-logic.md b/workshop/15-conditional-logic.md
index 365c5a0d..71a1a7d4 100644
--- a/workshop/15-conditional-logic.md
+++ b/workshop/15-conditional-logic.md
@@ -47,7 +47,7 @@ The skill adds this step to the frontmatter `steps:` block and recompiles the lo
Open your daily-status workflow file (e.g., `.github/workflows/daily-status.md`) and add the following block inside the YAML frontmatter under `steps:`:
-```markdown
+```markdown .github/workflows/daily-status.md
---
steps:
- name: Count recent commits
@@ -64,7 +64,7 @@ After adding it, run `gh aw compile` to regenerate the lock file.
Here is the step structure the skill will add:
-```markdown
+```markdown .github/workflows/daily-status.md
---
steps:
- name: Count recent commits
@@ -89,7 +89,7 @@ This shell command uses `git log` with a `--since` time filter to list only comm
In the same frontmatter block, add a top-level `if:` key at the same indentation level as `on:` and `steps:`:
-```markdown
+```markdown .github/workflows/daily-status.md
---
if: steps.recent.outputs.commit_count != '0'
---
diff --git a/workshop/16-connect-data-source.md b/workshop/16-connect-data-source.md
index a478a210..dabe317f 100644
--- a/workshop/16-connect-data-source.md
+++ b/workshop/16-connect-data-source.md
@@ -57,7 +57,7 @@ Here is what the first step looks like — the skill will add this for you:
First, fetch the recent commit log:
-```markdown
+```markdown .github/workflows/daily-status.md
- name: Fetch recent commits
id: recent # step ID — referenced as steps.recent.outputs.…
run: |
@@ -75,7 +75,7 @@ First, fetch the recent commit log:
Next, add a step to fetch open issues:
-```markdown
+```markdown .github/workflows/daily-status.md
- name: Fetch open issues
id: issues # step ID — referenced as steps.issues.outputs.…
run: |
@@ -101,7 +101,7 @@ Next, add a step to fetch open issues:
The AI prompt lives in the Markdown body after the frontmatter. Update that section so it uses the step outputs:
-```markdown
+```markdown .github/workflows/daily-status.md
---
# … your existing frontmatter with the two new steps …
---
diff --git a/workshop/17-add-mcp-tools.md b/workshop/17-add-mcp-tools.md
index a58a27e1..fac81dfa 100644
--- a/workshop/17-add-mcp-tools.md
+++ b/workshop/17-add-mcp-tools.md
@@ -56,7 +56,7 @@ The skill adds the `tools:` block and updates the brief. Review the diff before
Here is the `tools:` block the skill will add:
-```markdown
+```markdown .github/workflows/daily-status.md
---
name: Daily Status Report
on:
@@ -99,7 +99,7 @@ Open your daily-status workflow file (`.github/workflows/daily-status.md`) and f
Below the frontmatter, update the task brief to tell the agent it can use the MCP tools:
-```markdown
+```markdown .github/workflows/daily-status.md
You have access to GitHub tools via MCP. Use them to:
1. Fetch the last 5 commits on the default branch.
2. List all open issues labelled `bug`.
diff --git a/workshop/18-share-and-reuse.md b/workshop/18-share-and-reuse.md
index a13573c8..b9a0971d 100644
--- a/workshop/18-share-and-reuse.md
+++ b/workshop/18-share-and-reuse.md
@@ -74,7 +74,7 @@ Your teammate runs this inside their repository. `gh aw add` copies the Markdown
Add a short comment at the top of your workflow's Markdown task brief so users know what to customise:
-```markdown
+```markdown .github/workflows/daily-status.md
```
diff --git a/workshop/19-research-driven-training-node.md b/workshop/19-research-driven-training-node.md
index bc218866..69fed6a1 100644
--- a/workshop/19-research-driven-training-node.md
+++ b/workshop/19-research-driven-training-node.md
@@ -49,7 +49,7 @@ Write a one-paragraph node scope and list the exact [artifacts](https://github.g
Add XML comments to preserve reasoning without interrupting learner flow:
-```markdown
+```markdown workshop/28-safe-outputs-selection.md