All skills
Skillintermediate

workflowDocument store — Agent Guidelines

Every composable in this folder follows a two-layer pattern:

Claude Code Knowledge Pack7/10/2026

Overview

workflowDocument store — Agent Guidelines

Core pattern: apply/public method split

Every composable in this folder follows a two-layer pattern:

Public methods (exposed) — represent user intent. Handle normalization, deduplication, and preparation. Call apply methods internally.

Apply methods (private) — the only functions that mutate refs. Each apply method writes to the ref and fires an event hook. Never expose apply methods from the composable.

Component → publicMethod() → normalize → applyXxx() → ref + event hook

This split exists to support CRDT in the future: local user actions, remote CRDT sync, and undo/redo all converge on the same private apply methods inside the composable.

Event hooks

Every composable exposes change notifications via createEventHook from @vueuse/core. Event payloads must extend ChangeEvent from ./types.ts:


type MyChangeEvent = ChangeEvent<{ /* domain-specific fields */ }>;
const onMyChange = createEventHook();
  • Fire void onMyChange.trigger(...) inside every apply method
  • Expose only the .on subscriber: onMyChange: onMyChange.on
  • Use CHANGE_ACTION.ADD | UPDATE | DELETE for the action field

Adding a new composable — checklist

  1. Create event hook with typed payload extending ChangeEvent
  2. Write private apply*() methods — each mutates the ref and fires the hook
  3. Write public methods — normalize input, then call apply
  4. Return: readonly refs, public methods, onXxxChange: hook.on
  5. Never return apply methods

Anti-patterns

Don'tDo instead
Mutate refs outside apply methodsAll ref writes go through apply
Expose apply methods from composableKeep them private (not in return)
Use action objects / onChange routerPublic methods call apply directly
Use dataPinningEventBus or global event busUse scoped createEventHook
Import global stores inside composableInject dependencies via function params

Dependency injection

Composables receive external dependencies as constructor params, not via global store imports. This keeps them testable and makes coupling explicit:


  getNodeByName: (name: string) => INodeUi | undefined;
}) { ... }

Reference implementation

See useWorkflowDocumentActive.ts — the simplest complete example of the apply/public pattern with event hooks.