Skip to content

feat(setup): card-based skill library with linkable sources and auto-update - #78

Merged
dizys merged 14 commits into
dizys:mainfrom
0libote:feat/skills-cards
Nov 1, 2026
Merged

dizys merged 14 commits into
dizys:mainfrom
0libote:feat/skills-cards

Conversation

@0libote

@0libote 0libote commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

The old Skills view put skills in rows and providers in columns. Locating a skill or comparing agent access meant scanning a wide matrix. Repository tracking and manual update checks already worked for skills installed from a source; the gap was linking an existing editable skill after installation and choosing automatic updates per skill.

The default view is now one card per installed skill. Each card shows its name, description and how many agents can use it. Click a card to see its locations, agent access and source details. Skills with the same name from different locations remain separate entries.

The inspector lets you link an existing editable skill to a repository, opt it into automatic updates, or unlink the source. Updates → Automatic updates now has a Skills switch: it checks tracked sources on schedule and installs updates for opted-in skills when the server is idle. Manual checks remain available. Cards/Table, agent scope and bundled-skill visibility are inline controls that remember their settings.

All comparison images use the same 1440×900 frame.

Before After
Library Skills in a wide agent-by-skill matrix One card per installed skill
Options Agent columns and bundled-skill settings in the View menu Cards/Table, agent scope and Bundled controls inline

Skill inspector

The same frontend-design skill appears in both panels. Source tracking was already present; the updated inspector adds per-skill auto-update and unlink controls.

Focused before-and-after comparison of the frontend-design skill inspector

Validation:

  • node --test tests/*.test.mjs: 1070 pass, 0 fail (updated the View-menu test for the inline controls and the auto-update view test for the new policy).
  • Live smoke test inside the container: link → update check reports available → auto-update off/on → tracked once → unlink clears, plus an origins round-trip check.
  • Deployed to my live server (t3code container healthy, setup page HTTP 200) and clicked through cards, the inspector link flow and the Updates switch.

Follow-up before merge

I merged main into this branch and finished the open points from the review in 76cd06e. Some of the description above no longer matches. Table is the default again, and agent scope and bundled skills are back in the View menu.

Library

  • Table stays the default. Cards is an option beside View and is remembered in the browser.
  • Cards keep the table's folder groups, so same-named skills stay apart and bundled skills stay collapsed. Each card names any agent that limits the skill, for example "Ask in OpenCode".
  • Phones keep the grouped list in either layout.
  • Agent scope and bundled skills are back in the View menu, so there is no bare "+2" toggle or amber "Bundled" button.
  • The inspector drops the "Access & usage" section, which repeated the agent list, file count and auto-update setting just above it. The "Link source" box also gets proper padding.

Auto-updates

  • The idle pass installs only what the scheduled check found. It no longer fetches every opted-in source on each 5-minute tick.
  • Each automatic review is discarded afterwards, so "Install from source" doesn't hit the three-preview limit.
  • A skill linked from a copy that already differed from its source waits for one update reviewed by hand. Setup can't tell an older copy from a customized one, so it doesn't guess.
  • Reinstalling a skill from a different source starts with auto-update off. Updates from the same source keep the setting.
  • Turning on only the Skills switch no longer records "Auto-update turned off".

Docs cover the layout switch, linking, and the two opt-ins. The browser audits are back to main's View menu, with a new Cards check.

Screenshots (main vs. this branch, same fixtures, light)

Before (main) After
Library, 1280px Skills table on main Skills table with the new Table and Cards switch
Cards, 1280px (none) Cards grouped by folder, naming limiting agents
Phone, 390px Grouped phone list on main Grouped phone list, unchanged
Tracked skill Inspector source section on main Inspector with auto-update and unlink
Untracked skill Inspector without a source on main Inspector with Link source
Automatic updates Automatic updates on main Automatic updates with a Skills switch

Checks

  • node --test tests/*.test.mjs: 1089 pass, 0 fail.
  • skills-ui-audit (all six layouts, both themes, and the tab frames), skills-hooks-ui-audit, skills-update-ui-audit, auto-update-ui-audit and harness-ui-audit pass against the fixture console.

The OpenCode config change is split out as #80 and isn't part of this PR.

🤖 Generated with Claude Code

Phone widths hide the Cards/Table switch (zero-size) and collapse the
skills chipbar (display:none); the audit clicked both raw. Use the visible
skills.agents-all rendering, seed Table view per combo (fresh profile),
expand collapsed system groups before rows-vs-cards comparison, and wait
attached for hidden table rows.
@dizys

dizys commented Nov 1, 2026

Copy link
Copy Markdown
Owner

Hi @0libote, thank you for this! The skill inspector is a really nice addition. One click shows a skill's agents, source and location, it works well from the keyboard, and focus comes back to the card when it closes. The Skills switch also fits naturally next to the other categories under Automatic updates. And thanks for b290251; the new CI run is queued on it now.

I don't think it's ready to merge yet, though. Most of it comes down to two things: automatic updates can overwrite local edits, and the OpenCode change.

Before merging

  1. Automatic updates replace local edits without asking. A manual update asks you to tick "Replace my local edits" first, but the automatic path calls installUpdate(preview.previewId, preview.planId, true) without looking at preview.localChanges (docker/setup/server.mjs:2330). If someone edits an opted-in skill and the source moves on, their edits are gone the next time the server is idle. I'd skip skills with local changes and flag them in Updates instead.

  2. Linking turns automatic updates on, with the local copy as the baseline. linkSource defaults autoUpdate to true (docker/setup/skills.mjs:350), and the inspector always sends autoUpdate: true (client/skill-inspector.js:174). The recorded fingerprint is the local folder's, so linking a customized skill to its upstream reports an update right away, without treating the customization as a local change, and the next idle pass installs over it. Could links default to off? Also, when a source contains a single skill with a different name, it gets linked anyway (skills.mjs:368). A name mismatch probably deserves a confirmation.

  3. The per-skill opt-in resets after one update. Every install writes a fresh origin file with autoUpdate: false, manual: false (docker/setup/skills/imports.mjs:135), so the "Auto-update this skill" checkbox quietly unticks itself after the first automatic update. Replacing a tracked skill should carry its flags over.

  4. The OpenCode change would be better as its own PR. I understand the reason (OpenCode 2.x's watcher and symlinked skills//agents/ folders), but it changes persistence for existing containers:

    • ~/.config/opencode used to link to $T3CODE_HOME/agents/.config_opencode on the state volume. ensure_opencode_config replaces it with a real folder and copies over only opencode.json(c) and a linked AGENTS.md. Skills, agents and commands already saved there stay on the state volume but are no longer read.
    • New OpenCode skills now live in the home folder, so a deployment that mounts only the state volume loses them when the container is recreated.
    • A symlinked skills/ or agents/ folder is replaced with an empty one on every start.

    Would exporting OPENCODE_CONFIG_DIR to a real folder on the state volume work instead? That keeps everything where it is today, with no symlinks for the watcher to trip over.

  5. Green CI on the final head, including the image smoke tests. One note on the audit fix: on phones the Skills header is hidden, so there is no Cards/Table switch, and the audit now seeds Table view through localStorage and clicks the hidden button. That tests a view phone users can't reach, which ties into the next section.

Design

The cards are easy to scan, but as the default view they drop a lot of what the table showed:

  • Per-agent exceptions disappear. Off, Name only, Manual only and Denied all collapse into "N agents can use". For example, a skill that Claude Code has turned off and OpenCode denies just shows "1 agent can use".
  • Folders are gone. Skills are files in agent folders. The table grouped them by folder ("Claude Code folder · read by OpenCode and Muse Code") with a "Copy to…" action per folder. Cards are one flat list.
  • Same-named skills look identical. A user's own skill-creator and Codex's built-in one can only be told apart by opening them.
  • Bundled skills crowd the grid. Codex's built-in skills each get a full card instead of one collapsed row, and the amber "Bundled" button reads like a warning.
  • Phones only get Cards, since the switch is hidden there.
  • A few controls are unclear: a bare "+3" label, and the agent-scope toggle does nothing in Cards view.

My suggestion would be to keep Table (and the phone list) as the default, with Cards as an option. Alternatively, cards could show their folder and any per-agent exceptions, grouped by folder.

Smaller notes

  • The idle install pass calls checkUpdate for every opted-in skill on each 5-minute tick, so sources are fetched far more often than the configured check interval.
  • Automatic installs don't discard their previews, so afterwards "Install from source" can refuse for up to ten minutes ("Close another source preview…"). With more than three updates in one pass, the rest fail until previews expire.
  • Copy: a few new strings use em dashes (for example "Container folders can't auto-update — use Install from source"), and the footer says "Click a card" in Table view too.
  • docs/context-management.md describes a "View" control and a card menu that aren't in the UI.

None of this is a "no". The direction makes sense, and the inspector in particular is a clear improvement. Happy to help with any of these, including splitting out the OpenCode part, if that's useful. Thanks again!

Phones hide the Cards/Table switch (zero-size) and the skills
chipbar (display:none); the audit clicked both raw. Use the visible
skills.agents-all rendering, assert cards (not table rows) on phones
with self-calibrating counts from the tab and chip badges, wait
attached for hidden table rows, and expand groups through whichever
group toggles are visible.
…rces

Idle auto-installs now skip skills with local changes instead of
overwriting them; the update stays available in Updates for an
explicit review. Linking a source defaults to manual-only, and
linking a single differently named skill requires confirmation.
Tracked replacements carry auto-update flags over instead of
resetting them. Also fixes footer/docs wording and em dashes.
The OpenCode 2.x watcher fix changes persistence for existing
containers and belongs in its own PR. This reverts de53d31,
a3851c1 and caae2ab; the reworked approach will follow separately.

Revert "fix(opencode): use real config dirs, strip invalid skills key"
Revert "fix(opencode): tolerate unset T3_INFRA_NODE under set -u in persist test"
Revert "fix(tests): isolate OpenCode config resolution from runner env"
@0libote

0libote commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor Author

Done, split as suggested: the OpenCode change is reverted out of here and reworked as #80, which exports OPENCODE_CONFIG_DIR at a real folder on the state volume instead of symlinking anything. State-dir contents (skills, agents, opencode.json) are read in place, the redundant home link is dropped only when it resolves to the same dir, and AGENTS.md follows the same override. MCP saves also strip the legacy top-level skills key now.

On the blocking items:

  1. Idle auto-installs skip skills with local edits (server.mjs gates on a new autoInstallable() check next to the review that reports localChanges); the update stays flagged in Updates for manual review.
  2. linkSource defaults to manual-only (skills.mjs), the inspector no longer sends autoUpdate: true, and linking a single differently named skill returns a mismatch error asking for confirmation instead of silently linking.
  3. Tracked replacements carry autoUpdate/manual (and linkedAt) over in imports.mjs, for both update installs and manual re-imports that replace a tracked folder.

Smaller notes are fixed too: em dashes removed from the new strings, the library footer reads "Click a card"/"Click a row" per view, and the docs no longer describe a View menu or card menu.

Two things I deliberately left: the cards-vs-table default (your call — happy to flip the default or add folder/exception info to cards as a follow-up), and the +N toggle doing nothing in Cards view, which follows from the same default-view question.

CI is running on both heads (pushed just now); will report back on green.

0libote and others added 3 commits November 1, 2026 11:27
Cards are the default view, so the library readiness gate and the
skill-row click targets must also match cards, not just table and
phone-list rows.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Follow-up to the review on dizys#78.

Library:
- Table stays the default. Cards are an option beside View, keep the
  folder groups (so same-named skills stay apart and bundled skills stay
  collapsed), and name each agent that limits a skill.
- Phones keep the grouped list in either layout.
- Agent scope and bundled skills go back to the View menu, so there is no
  bare +N toggle or amber Bundled button.
- The inspector drops the Access & usage section, which repeated the
  agent list, file count and auto-update setting above it, and the Link
  source box gets proper padding.

Auto-updates:
- The idle pass installs only what the scheduled check found, instead of
  fetching every opted-in source on each tick.
- It frees each review slot afterwards, so Install from source stays
  available.
- A skill linked from a copy that already differed from its source waits
  for one reviewed update, since Setup can't tell an older copy from a
  customized one.
- A reinstall from a different source starts opted out.
- Turning on only the Skills switch no longer logs "Auto-update turned
  off".

Docs describe the layout switch, linking and the two opt-ins; the audits
are back to main's View menu with a new Cards check.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
dizys added a commit that referenced this pull request Nov 1, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@dizys
dizys merged commit 23a010b into dizys:main Nov 1, 2026
13 checks passed
@0libote
0libote deleted the feat/skills-cards branch November 1, 2026 13:38
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