Suede#
SvelteKit starter template. Entry point for stack, conventions, and process: AGENTS.md.
For self-hosted knots, clone URLs may differ based on your setup.
The task-note lifecycle (AGENTS.md task-lifecycle skill) requires
an entry per completed task; these were authored at the time of
their respective work but never committed. Closing the loop:
- 2026-06-03-03: chronver release process
- 2026-06-04-01: remove Claude-Code-specific artifacts from
deciduous install
- 2026-06-04-02: build the deciduous decision graph for Suede
from commit history
Plus the plan artifact for the chronver task
(agent-notes/plans/add-suede-release-process-chronver.md) —
plan files are write-only at task end per the skill, so this
is the canonical place for it.
- .opencode/agents/deciduous.md: specialist agent for
deciduous decision-graph operations.
- .opencode/commands/*.md (10 files): slash-command wrappers
for the most common workflows (work, build, document,
decision-graph, decision, recover, serve-ui, sync, sync-graph,
build-test).
- .opencode/plugins/*.ts (3 files): lifecycle hooks —
post-commit-reminder, require-action-node (Edit/Write
guard), version-check.
- .opencode/skills/{archaeology,narratives,pulse}/SKILL.md:
in-repo skills for narrative-driven decision-graph work.
- .opencode/tools/deciduous.ts: thin TS tool wrapper for the
deciduous CLI used by the agents/commands above.
- opencode.json: project-level opencode config (model,
agent list, MCP servers, etc.).
Also includes a stray prettier reformat of .storybook/preview.ts
(the import chain was unchanged; only whitespace/indentation
differed from the version committed in b718ad0).
Excluded: .opencode/.gitignore (workspace-internal config that
self-excludes via its own last line), .opencode/node_modules/,
.opencode/package.json, .opencode/package-lock.json
(gitignored at the repo root by the prior commit).
The .opencode directory is a pnpm-managed workspace (its own
internal .opencode/.gitignore covers node_modules + lockfiles
for the pnpm tooling). Git only reads the root .gitignore for
untracked-detection, so add the corresponding entries here to
keep 'git status' clean for downstream contributors.
The tracked .opencode/ contents (agents, commands, plugins,
skills, tools, and the .opencode/.gitignore itself) are
configuration and ship with the repo.
- .github/workflows/cleanup-decision-graphs.yml: scheduled (and
manual-dispatch) cleanup of stale deciduous event log files.
Companion to the deciduous sync export at docs/graph-data.json.
- .github/workflows/deploy-pages.yml: builds the Storybook
static site (pnpm build-storybook) and deploys storybook-static/
to GitHub Pages. This is what makes the SuedeButton docs
(and any future Storybook) browsable from the public web.
Neither workflow has been exercised against the live repo yet;
add a PR for the deploy workflow to fire on a tag or manual
dispatch only.
One-line content edit; the SvelteKit default 'Welcome to SvelteKit'
page no longer reflects the project's identity. Now reads
'<h1>suede</h1><p>a template repo.</p>'. No functional change;
the +page.svelte component is otherwise unchanged.
Removes the auto-generated example Button/Accordion wrappers and
their Vitest specs that were scaffolded in 341d364
('feat: install bits-ui and stylebase, scaffold UI wrappers') but
never replaced with real components. The matching story files
that referenced them were removed in bbdd827 (broken imports
were blocking Storybook's vite import-analysis).
What's left in src/lib/components/ui/ is the new SuedeButton
wrapper (added in c7c153b) — the only wrapper the project
currently ships. Future wrappers should be added here as
they're built.
The SuedeButton wrapper was applying the same .suede-button styles
to both the <button> and <a> renderings of bits-ui's polymorphic
Button.Root. By design, an anchor acting as a button (e.g. a
'Subscribe' link that navigates to a checkout page) should look
like a button — but a literal <a href> link should look like a
link. Until now the two were visually indistinguishable.
Added a :global(.suede-button[href]) rule that overrides the
button styling when bits-ui renders an anchor (it sets the
href attribute on the underlying element):
background-color: transparent
color: var(--hue-blue-500)
padding-inline: 0
text-decoration: underline
text-decoration-thickness: from-font
text-underline-offset: 0.2em
plus a :hover variant that darkens the color to --hue-blue-600.
The existing :hover and :active rules are now scoped with
:not([href]) so they only apply to the button variant — without
that, their higher-specificity background-color: var(--hue-blue-600)
would have re-painted the link blue on hover, defeating the
transparent background.
The user also renamed the destructured class prop from `klass`
to `className` (React convention) and updated the
'With class override' story to pass `class="u:fs-1"` instead
of `u:fs-3`, so the demo now isolates the inline-style
background override (emerald) without compounding it with a
font-size change.
Verified via Playwright computed-style inspection on all 4 stories:
Primary bg=oklch blue, white text, no underline (button)
Disabled same blue, cursor=not-allowed (button)
As link bg=transparent, blue text, underlined (link!)
With class override bg=oklch emerald, white text, no underline (button, color override)
pnpm check still 0 errors / 0 warnings project-wide.
SvelteKit starter template. Entry point for stack, conventions, and process: AGENTS.md.