Skip to content

Render skill markdown, clickable resources, and hardened resource panel - #261

Merged
mattprintz merged 7 commits into
devfrom
feature/rendered-skill-resources
Aug 25, 2026
Merged

mattprintz merged 7 commits into
devfrom
feature/rendered-skill-resources

Conversation

@brandomr

@brandomr brandomr commented Aug 24, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Skill content in the integrations UI previously displayed as raw markdown in a read-only code editor, and the resource/example listings were inert. This PR makes skills readable and navigable, and fixes several correctness issues found while hardening the result.

Rendering and navigation

  • Markdown resources (SKILL.md, references, examples) render as HTML instead of raw source, in both the center pane and the right-side resource panel. Raw source stays one click away via an Edit/Preview toggle (Raw/Preview for read-only skills).
  • Available Resources and Code Examples lists are clickable and open the file rendered in the resource panel. The lists are a shared SkillResourceLinks component used by both the read-only viewer and the editor.
  • Relative links between a skill's markdown files (e.g. references/FILTERS.md, ../assets/x.yaml) previously navigated the app to a 404. They now resolve against the linking file's directory (with a skill-root fallback and percent-decoding) and open the target resource in the panel. External links are untouched.
  • SKILL.md instructions clamp to a preview height with a Show more/Show less toggle, shown only when content actually overflows (re-measured on resize and image load). Without this, long instructions buried everything below them.
  • Wide code blocks and tables scroll inside their own box instead of stretching the pane horizontally (flex items needed min-width: 0).

Correctness and security

  • All rendered integration markdown is sanitized with DOMPurify before hitting v-html. Skills can arrive from remote URLs and uploads, so unsanitized rendering was an XSS vector into a page holding a live kernel connection.
  • The resource panel had two data-loss paths, both fixed: a stale fetch response could land in (and be saved over) a different resource than the one it was requested for, and a silently-failed load left Save enabled on an empty draft, which would wipe the file. Failures now display, Save is disabled until content is loaded, and unsaved drafts prompt before being discarded.
  • Only .md/.markdown files are treated as markdown; other file types always open in the code editor rather than rendering garbled.
  • Integration list descriptions are rendered in a cached computed instead of inline in the template, which was re-running parse+sanitize on every hover change and search keystroke.

Build and cleanup

🤖 Generated with Claude Code

brandomr and others added 7 commits August 24, 2026 09:49
Skill resources previously displayed as raw markdown in a read-only code
editor, and the resource/example lists in the read-only skill viewer were
inert.

- SkillResourcePanel: markdown resources open in a rendered view; editable
  resources get an Edit/Preview toggle, read-only ones are rendered only.
  Non-markdown resources keep the code editor.
- SkillIntegrationViewer: show the SKILL.md instructions (rendered), and
  make Available Resources / Code Examples items clickable, opening the
  resource focused in the right-side panel.
- IntegrationsInterface: wire the open-resource event to the right panel
  via its exposed focusResource().

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KxxsV6UyDEGTBGsMP4jeLy
The html build target ran only build-ui, skipping the routes step, so a
dev server built via make init had no routes.json and 404'd every page
route (/notebook, /integrations, ...).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KxxsV6UyDEGTBGsMP4jeLy
Editable skills (e.g. from the global ~/.beaker/skills root) opened
straight into a raw SKILL.md code editor with no way to browse the
skill's resources from the center pane.

- Instructions default to a rendered markdown preview with an
  Edit/Preview toggle; new or empty skills start in the editor.
- Add the clickable Available Resources / Code Examples lists (as in the
  read-only viewer), opening the resource rendered in the right panel.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KxxsV6UyDEGTBGsMP4jeLy
Long unbreakable lines in rendered code blocks propagated their intrinsic
width up through the fieldset flex items (min-width: auto), stretching the
center pane sideways. Let fieldsets shrink (min-width: 0) and constrain
pre/table/img inside rendered markdown to scroll within their own box.

Relative links between a skill's markdown files (references/REST-API.md,
../references/X.md, examples/Y.md) navigated the app to a 404. Intercept
clicks on relative hrefs in rendered markdown, resolve them against the
linking file's directory, and open the matching resource in the resource
panel; unresolvable relative links become no-ops and external links are
untouched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KxxsV6UyDEGTBGsMP4jeLy
A full SKILL.md runs to thousands of pixels and buried the Available
Resources / Code Examples sections below it. Extract a ClampedMarkdown
component that caps rendered markdown at a preview height with a fade-out
and a Show more/Show less toggle, shown only when the content actually
overflows; use it for the instructions in both the skill editor and the
read-only viewer. Relative-link interception passes through unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KxxsV6UyDEGTBGsMP4jeLy
- Rendered integration markdown (skill instructions, resource files, MCP
  descriptions) went into v-html unsanitized; skills can arrive from
  remote URLs and uploads, so route all integration marked.parse calls
  through renderMarkdown(), which sanitizes with DOMPurify. Lives in
  util/markdown.ts alongside the existing marked/KaTeX setup.
- Delete ResourceViewer and ExamplesPanel: unreferenced since the skill
  editor rework (#252), and ResourceViewer still carried debug logging.
- Unit-test isRelativeHref/resolveResourceFromHref (.., ./, fragments,
  query strings, externals) and renderMarkdown's sanitization.
- Show empty custom-metadata values as blank instead of "null".

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KxxsV6UyDEGTBGsMP4jeLy
Correctness (from adversarial review of the branch):
- openResource: guard against stale fetch responses (a slow load for
  resource A no longer lands in — or gets saved over — resource B), track
  load failures visibly, and disable Save while content is loading or
  failed so a blank draft can't overwrite the file on disk.
- Confirm before discarding an unsaved draft when navigation (row click,
  rendered link, center viewer, Back) opens another resource.
- Only treat .md/.markdown files as markdown (a .csv/.txt no longer
  renders garbled through marked), and offer the Raw/Preview toggle on
  read-only markdown too, so the exact content the agent receives is
  always viewable.
- Resolve relative links with a skill-root fallback (examples/ files use
  root-relative paths) and percent-decode hrefs before matching.
- Don't yank the user out of the raw instructions editor when a resource
  refresh re-syncs state; flip to preview only when instructions first
  arrive into an empty editor.
- ClampedMarkdown re-measures overflow on element resize and captured
  image loads, so late reflow can't clip content below an unreachable
  fold.
- IntegrationPanel: render+sanitize descriptions in a cached computed
  instead of inline in the v-for (was re-sanitizing every card on every
  hover change and keystroke).

Structure:
- Deduplicate the relative-link click handling into
  resourceFromLinkClick() (was copy-pasted three times).
- Extract the Available Resources / Code Examples fieldsets into
  SkillResourceLinks (was duplicated between viewer and editor).
- Move the shared .skill-description prose styles into index.scss;
  components no longer depend on another component's style block.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KxxsV6UyDEGTBGsMP4jeLy
@brandomr
brandomr requested a review from mattprintz August 24, 2026 16:12

@mattprintz mattprintz left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great.

@mattprintz
mattprintz merged commit b12e9de into dev Aug 25, 2026
4 checks passed
@mattprintz
mattprintz deleted the feature/rendered-skill-resources branch August 25, 2026 19:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants