Uh oh!
There was an error while loading. Please reload this page.
Add a Copilot Canvas extension for agentic workflow operations - #42137
Conversation
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
pelikhan
commented
Jun 28, 2026
|
pelikhan
commented
Jun 28, 2026
@copilot a tabbed view design so that it is easy and modular to add views |
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Implemented in
|
pelikhan
commented
Jun 28, 2026
@copilot modularize to allow reuse, apply SOLID, DRY, YAGNI. |
pelikhan
commented
Jun 28, 2026
@copilot also wire gh aw audit-diff and gh aw compile commands |
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
pelikhan
commented
Jun 28, 2026
|
pelikhan
commented
Jun 28, 2026
@copilot init impeccable (https://github.com/pbakaus/impeccable) for the canvas Configure it as a github.com like experience for exploring, managing, running agentic workflows. |
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Addressed in 2735ec5 and 6dfe1c2. I refactored the dashboard to a reusable tab model with shared view-switch helpers, removed duplicated run-detail navigation logic, and added guarded tab selection for cleaner SOLID/DRY behavior while keeping scope minimal.
Implemented in 2735ec5 and finalized in 6dfe1c2. The dashboard now uses a metadata-driven tabbed view system (Workflows/Runs/Run details/Commands), with each view rendered as an independent panel to make future view additions modular. |
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Implemented in 06e1f42 (plus follow-up polish in 4e3d023): wired
Implemented in 06e1f42: initialized Impeccable context for this canvas with |
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
pelikhan
commented
Jun 28, 2026
/matt |
🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅ |
There was a problem hiding this comment.
Pull request overview
This pull request introduces a project-scoped GitHub Copilot Canvas extension that provides a lightweight “agentic workflows” dashboard surface (definitions, runs, run details, and a command panel), along with build/lint/fmt targets wired into the repo Makefile.
Changes:
- Added a new Copilot Canvas extension under
.github/extensions/agentic-workflows-dashboard, including the extension entrypoint (extension.mjs) and a static dashboard UI (Primer CSS styling + Alpine.js-driven views). - Introduced a strict TypeScript domain model + pagination helper (with Vitest coverage for pagination) and compiled runtime assets under
web/. - Integrated extension formatting/linting/testing into top-level
make fmt,make lint, and added a dedicatedtest-canvas-extensiontarget.
Show a summary per file
| File | Description |
|---|---|
| Makefile | Adds build/test/fmt/lint targets for the Canvas extension and wires fmt/lint into existing top-level targets. |
| .github/extensions/agentic-workflows-dashboard/web/styles.css | Adds minimal dashboard-specific CSS utilities (shell spacing, scroll containers, selection styling). |
| .github/extensions/agentic-workflows-dashboard/web/pagination.js | Adds web runtime pagination helper used by the dashboard bundle. |
| .github/extensions/agentic-workflows-dashboard/web/models.js | Adds an (empty) module stub emitted for TS module boundary. |
| .github/extensions/agentic-workflows-dashboard/web/index.html | Adds the dashboard HTML template (Primer layout, tabbed panels, and markdown summary rendering surface). |
| .github/extensions/agentic-workflows-dashboard/web/app.js | Adds the dashboard’s Alpine.js app runtime (definitions/runs datasets, command simulation, safe markdown rendering). |
| .github/extensions/agentic-workflows-dashboard/vitest.config.ts | Configures Vitest discovery for extension tests. |
| .github/extensions/agentic-workflows-dashboard/tsconfig.json | Defines strict TypeScript compilation settings and emits JS into web/. |
| .github/extensions/agentic-workflows-dashboard/test/pagination.test.ts | Adds unit tests for pagination behavior. |
| .github/extensions/agentic-workflows-dashboard/src/pagination.ts | Adds typed pagination helper used by TS sources. |
| .github/extensions/agentic-workflows-dashboard/src/models.ts | Adds strict domain model types for definitions, runs, steps, and paged results. |
| .github/extensions/agentic-workflows-dashboard/src/app.ts | Adds typed dashboard runtime (rendering logic, command simulation, and safe markdown rendering). |
| .github/extensions/agentic-workflows-dashboard/PRODUCT.md | Documents product intent and UI design lane for the extension. |
| .github/extensions/agentic-workflows-dashboard/package.json | Defines extension package scripts/deps (build, lint, test, fmt). |
| .github/extensions/agentic-workflows-dashboard/package-lock.json | Locks dependency tree for the extension. |
| .github/extensions/agentic-workflows-dashboard/extension.mjs | Implements the Copilot Canvas extension (actions, in-memory data, and dashboard open() URL rendering). |
| .github/extensions/agentic-workflows-dashboard/copilot-extension.json | Adds Copilot extension metadata (name/version). |
| .github/extensions/agentic-workflows-dashboard/.impeccable/config.json | Enables Impeccable detector config for the dashboard’s web assets. |
Review details
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Files not reviewed (1)
- .github/extensions/agentic-workflows-dashboard/package-lock.json: Generated file
- Files reviewed: 17/20 changed files
- Comments generated: 8
- Review effort level: Low
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
| export function paginate<T>(items: T[], page: number, pageSize: number): PagedResult<T> { | ||
| const totalItems = items.length; | ||
| const totalPages = Math.max(1, Math.ceil(totalItems / pageSize)); | ||
| const safePage = Math.min(Math.max(1, page), totalPages); | ||
| const start = (safePage - 1) * pageSize; | ||
| const end = start + pageSize; | ||
| return { | ||
| items: items.slice(start, end), | ||
| page: safePage, | ||
| pageSize, | ||
| totalItems, | ||
| totalPages, | ||
| hasNextPage: safePage < totalPages, | ||
| hasPreviousPage: safePage > 1, | ||
| }; | ||
| } |
| const status = statuses[index % statuses.length] ?? "queued"; | ||
| const definition = sourceDefinitions[index % sourceDefinitions.length]; | ||
| const stepStatuses = stepStatusMap[status] ?? stepStatusMap.queued; | ||
| return { | ||
| id: `run-${String(index).padStart(5, "0")}`, | ||
| definitionId: definition.id, | ||
| status, |
| </main> | ||
| </div> | ||
| <script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.15.0/dist/cdn.min.js"></script> | ||
| <script type="module"> |
| async function renderDashboardUrl() { | ||
| const htmlPath = join(__dirname, "web", "index.html"); | ||
| const appPath = join(__dirname, "web", "app.js"); | ||
| const cssPath = join(__dirname, "web", "styles.css"); | ||
| const [htmlTemplate, appBundle, cssBundle] = await Promise.all([readFile(htmlPath, "utf8"), readFile(appPath, "utf8"), readFile(cssPath, "utf8")]); | ||
| const html = htmlTemplate.replace("/*__APP_CSS__*/", cssBundle).replace("/*__APP_JS__*/", appBundle); | ||
| return `data:text/html;charset=utf-8,${encodeURIComponent(html)}`; | ||
| } |
| "devDependencies": { | ||
| "typescript": "6.0.3", | ||
| "vitest": "4.1.9" | ||
| }, | ||
| "scripts": { | ||
| "build": "tsc -p tsconfig.json", | ||
| "typecheck": "tsc -p tsconfig.json --noEmit", | ||
| "test": "vitest run", | ||
| "lint": "npm run typecheck && npm test", | ||
| "fmt": "npm run fmt:ts && npm run fmt:html && npm run fmt:css && npm run fmt:js && npm run fmt:json", | ||
| "fmt:ts": "npx prettier --write --parser typescript \"src/**/*.ts\" \"test/**/*.ts\" \"vitest.config.ts\"", | ||
| "fmt:html": "npx prettier --write --parser html \"web/index.html\"", | ||
| "fmt:css": "npx prettier --write --parser css \"web/styles.css\"", | ||
| "fmt:js": "npx prettier --write --parser babel \"extension.mjs\"", | ||
| "fmt:json": "npx prettier --write --parser json \"copilot-extension.json\" \"package.json\"", | ||
| "impeccable:detect": "npx impeccable detect web/index.html web/styles.css" | ||
| } |
Review complete: 3 blocking issues, 4 medium priorityApplied 🔴 Blocking (must fix)
🟡 Medium priority
@copilot please address the review comments above.
|
There was a problem hiding this comment.
Skills-Based Review 🧠
Applied /tdd, /zoom-out, /improve-codebase-architecture, /grill-with-docs, and /diagnose — requesting changes on three blocking issues.
📋 Key Themes & Findings
Blocking Issues
Mutable global state (
extension.mjs:116) —runs.unshift()mutates module-level state shared across all sessions. In any multi-user deployment this is a correctness bug.Test coverage gap (
test/pagination.test.ts) — 414-lineapp.tsand 353-lineextension.mjscontain complex branchy logic (renderSafeMarkdown,runGhCommand,dispatchWorkflow) with zero tests. The HTML injection surface and command parser both need coverage before this ships.Generated artifacts committed (
web/app.js) — TypeScript compiler output is checked in alongside source, creating silent drift risk on everysrc/*.tsedit.
Medium Priority
tsconfig.jsonexcludestest/— test files not type-checked bynpm run typecheckrunFlagMatchhoisted with implicit branch-ordering dependency — fragile, needs localisation and tests- Command handling duplicated between
extension.mjsandapp.tswith no documented relationship dispatchSelectedWorkflow()operates on a separate dataset from the canvasdispatchWorkflowaction — no documented design intent
Positive Highlights
- ✅ Clean domain model in
src/models.tswith strict TypeScript (noUncheckedIndexedAccess,exactOptionalPropertyTypes) - ✅ Generic
paginate<T>function with proper clamping and tested behaviour - ✅
escapeHtmlruns before all inline transforms — XSS fundamentals are sound - ✅ Makefile integration (
test-canvas-extension,lint-canvas-extension,fmt-canvas-extension) is well-structured - ✅ Progressive disclosure design in the Primer-based UI is clean and consistent
🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · 139.1 AIC · ⌖ 10.1 AIC · ⊞ 6.6K
Comment /matt to run again
…K dep - Replace data URI with a per-instance loopback HTTP server; the runtime rejects data: scheme URLs with canvas_provider_url_disallowed - Serve web/app.js and web/pagination.js as separate routes so the ES module import chain resolves correctly from the loopback origin - Add onClose handler to shut down the server when a panel is closed - Fix Alpine.js x-for directives: move them from <div> to <template> elements as required by Alpine v3 (list rendering was silently broken) - Remove @github/copilot-sdk from package.json dependencies; the CLI auto-resolves the SDK, and listing it risks installing a conflicting version if someone runs npm install Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Alpine's defer script fires alpine:init before the type=module app.js
has run, so Alpine.data('dashboardApp') was never registered and the
dashboard rendered blank.
Fix: import Alpine as an ESM module directly in app.js and call
Alpine.start() at the end of the module. This gives the module full
control over startup order — Alpine.data() is registered synchronously
before Alpine.start() walks the DOM.
- Remove the defer CDN script tag from index.html (Alpine is now
imported by app.js via the +esm CDN path)
- Remove the document.addEventListener('alpine:init', ...) wrapper;
register Alpine.data() at module scope instead
- Add Alpine.start() at the end of app.js
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>- extension.mjs: use execFile to call ./gh-aw (dev) or gh aw (installed); add /api/status, /api/runs, /api/run-command, /api/refresh routes; add 60s result cache; add systemMessage with CLI usage instructions; assign workspacePath after joinSession; remove all dummy data functions - web/app.js: fetch from /api/* endpoints; map real field names (workflow, engine_id, run_id, workflow_name, duration, token_usage, turns, error_count); add loadingDefinitions/loadingRuns/error state; add refresh() - web/index.html: update templates for real field names; add loading spinners; replace step list in Details tab with metrics grid; add Refresh button; update Commands tab quick-fill buttons to real commands Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
🤖 PR Triage — §28342769269
Score breakdown: Impact 42 · Urgency 15 · Quality 12 Rationale: New GitHub Copilot Canvas extension for agentic workflow operations (+2777/−2, 20 files). Significant new product surface: dashboard for browsing workflow definitions/runs, dispatching workflows, and invoking Next steps:
|
Uh oh!
There was an error while loading. Please reload this page.
Covers the week's highlights including: - Copilot Canvas extension for agentic workflow operations (PR #42137) - create-canvas skill (PR #42147) - sandbox.agent.sudo: false coverage hits 80% (PR #42119) - Code Scanning Fixer expanded to all severity levels (PR #42139) - mcpg v0.3.32 + firewall v0.27.13 bump (PR #42146) - Agent of the Week: agent-persona-explorer Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
🎉 This pull request is included in a new release. Release: |
This PR adds a project-scoped GitHub Copilot Canvas extension specialized for agentic workflows in
github/gh-aw. It introduces a minimal, GitHub-styled dashboard for browsing workflow definitions and runs, reviewing safe markdown step summaries, dispatching predefined workflows, and invokinggh aw logs/gh aw auditcommands at canvas level.Extension surface and wiring
.github/extensions/agentic-workflows-dashboardwith Copilot extension metadata and entrypoint.listDefinitions(page, pageSize)listRuns(page, pageSize)getRun(id)dispatchWorkflow(definitionId, inputs)runGhAwLogs(args)runGhAwAudit(args)Strict TypeScript domain model + paging
WorkflowDefinition,WorkflowRun,WorkflowStep, and genericPagedResult<T>.Dashboard UI (Alpine.js + Primer CSS, native modules)
gh aw logsgh aw logs --run <id>gh aw auditgh aw audit --run <id>Safe markdown rendering for run summaries