le-truc
Expert guidance for building reactive web components with the @zeix/le-truc library. Use when creating, reviewing, or debugging a Le Truc component.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Expert guidance for building reactive web components with the @zeix/le-truc library. Use when creating, reviewing, or debugging a Le Truc component.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
Keep le-truc developer-facing documents up to date with the source code and examples docs-src/pages/, README.md, ARCHITECTURE.md, AGENTS.md, JSDoc in src/, and skill files in .agents/skills/. Use after code changes, to verify consistency, or to update a specific document.
Maintains Architectural Decision Records (ADRs) for the le-truc project. Creates, updates, lists, and supersedes ADRs in the /adr/ directory.
Expert developer for the @zeix/le-truc library. Use when implementing features, fixing bugs, or answering questions about the library's internals, public API, architecture, or its relationship to @zeix/cause-effect.
Maintain CHANGELOG.md for the @zeix/le-truc library. Use after meaningful code changes, when asked to add release notes, or to prepare a release.
Expert developer for the le-truc docs build pipeline and dev server. Use when implementing features, fixing bugs, adding Markdoc schemas, writing tests, or answering questions about the Bun + Cause & Effect + Markdoc + TypeDoc + Shiki stack in server/.
Expert guidance for @zeix/cause-effect reactive primitives (signals, memos, tasks, sensors, slots, stores, lists, collections, scopes). Use for signal-level questions, choosing the right primitive, or debugging reactivity — in le-truc projects or standalone.
| name | le-truc |
| description | Expert guidance for building reactive web components with the @zeix/le-truc library. Use when creating, reviewing, or debugging a Le Truc component. |
| user_invocable | true |
This skill provides authoritative guidance for developing components with @zeix/le-truc, a reactive custom elements library. It covers the factory form of defineComponent, reactivity patterns, DOM binding, inter-component coordination, and accessibility.
Use this skill when:
For library development itself, use the project's own documentation in src/, ARCHITECTURE.md, REQUIREMENTS.md, and CONTEXT.md.
For signal-level questions, @zeix/cause-effect is re-exported by le-truc — no separate install needed.
One form: the factory form of defineComponent:
defineComponent<MyProps>('my-component', ({ expose, first, host, on, watch }) => {
const button = first('button', 'Add a native <button>.')
expose({ disabled: asBoolean() })
on(button, 'click', () => { /* ... */ })
watch('disabled', bindProperty(button, 'disabled'))
})
watch(), on(), pass(), each(), and provideContexts() register their effect automatically when called — no return needed. Explicit return [...] of the same descriptors still works but is deprecated. For a hand-authored EffectDescriptor not produced by any of these — e.g. wrapping a native IntersectionObserver — register it via watch(() => true, descriptor) (see the Factory Context table below).
The factory receives a FactoryContext at connect time with these helpers:
| Helper | Purpose |
|---|---|
first(selector, required?) | Query single descendant; throws if required string given and no match |
all(selector, required?) | Return Memo<E[]> backed by lazy MutationObserver |
host | Component host element, typed as HTMLElement & P |
expose(props) | Declare reactive properties — call once, imperatively |
watch(source, handler) | Create reactive effect descriptor |
on(target, type, handler, options?) | Create event listener descriptor |
pass(target, props) | Create slot-swap descriptor for Le Truc child |
provideContexts(contexts) | Create context-provider descriptor |
requestContext(context, fallback) | Return Signal<T> (backed by a Slot) for use inside expose() |
attribute at connect time → parser
↓
event / property set → host.prop (signal)
↓
watch(source, handler) re-runs
↓
DOM update via bind*
↓
on(el, type, handler) → { prop: value }
↓
signal updated → watch re-runs
Key constraint: host is the only external interface. Components read/write state through host.propName. No querying outside the host's subtree, no direct property access on child components.
Binding helpers connect signals to DOM properties/attributes:
| Helper | Purpose |
|---|---|
bindText(el) | Set text content |
bindProperty(el, key) | Set DOM property |
bindAttribute(el, name) | Set/remove attribute with security validation |
bindClass(el, token) | Toggle CSS class |
bindState(internals, token) | Toggle custom :state() pseudo-class — prefer over bindClass(host, token) for host state |
bindStyle(el, prop) | Set/remove inline style |
bindVisible(el) | Control hidden attribute |
| Relationship | Mechanism |
|---|---|
| Parent → Le Truc child | pass(target, props) — slot-swap |
| Ancestor → descendant (any depth) | provideContexts / requestContext |
| Parent → bubbled events | on(host, type, handler) |
| Parent → dynamic descendants | all(selector) + each() |
| Keyed data → container children | createList() + reconcile() — data-driven |
| Sibling → sibling | Not supported — lift to common ancestor |
| Term | Meaning | Avoid |
|---|---|---|
| Module | ESM file in src/ containing component definitions | component (file), library |
| Component | Web Component instance in DOM, managed by Le Truc | module (instance), element |
| Custom Element | DOM element defined via customElements.define() | Web Component (API), tag |
| Factory | Function passed to defineComponent() | builder, constructor |
| Factory Context | Object passed to factory with helpers | component context |
| Effect Descriptor | Thunk produced by watch(), on(), pass(), each(), provideContexts(), or hand-authored and registered via watch(() => true, descriptor) — auto-registered when produced by a helper, no return needed | effect, reaction |
| Signal | Reactive primitive from @zeix/cause-effect | state, observable |
| Slot | Wrapper enabling signal swapping for pass() and requestContext() | container, wrapper |
| Parser | Transforms HTML attribute string to typed value | converter, decoder |
| Binding | One-way signal→DOM connection via bind* | link, sync, pass |
| Pass | Zero-overhead signal sharing between Le Truc components | forward, share, bind |
What kind of task is this?
| Response | Workflow |
|---|---|
| 1, "build", "create", "new", "add", "write" | workflows/build.md |
| 2, "review", "extend", "refactor", "improve", "check" | workflows/review.md |
| 3, "debug", "fix", "broken", "not working", "wrong", "unexpected" | workflows/debug.md |
Intent-based routing: If the user provides clear context without selecting, route based on intent.
All references in references/:
| File | Contents |
|---|---|
component-model.md | defineComponent args, reactivity flow, re-exported signal API |
effects.md | Which bind* helper / effect to use when |
parsers.md | Initializers for expose(): asBoolean, asInteger, asString, defineMethod, etc. |
coordination.md | pass(), provideContexts/requestContext, on() on host, all() |
markup.md | HTML structure: progressive enhancement, semantic nesting, variants |
styling.md | CSS: host scoping, nesting, custom properties, variant classes |
documentation.md | What to document and how: property tables, descendant tables |
testing.md | Framework-agnostic testing patterns |
anti-patterns.md | What to avoid: TypeScript, HTML, CSS, documentation |
accessibility.md | ARIA roles, native semantics, ARIA APG patterns |
| Workflow | Purpose |
|---|---|
workflows/build.md | Create a new component (all four files) |
workflows/review.md | Review or extend an existing component |
workflows/debug.md | Diagnose and fix unexpected reactive behavior |
Always verify against:
src/ — the real implementationARCHITECTURE.md — mental model and constraintsREQUIREMENTS.md — functional and non-functional requirementsCONTEXT.md — precise domain vocabularyWhen in doubt, the source code is authoritative.