diff --git a/.gitignore b/.gitignore
index 034456d..4fa3931 100644
--- a/.gitignore
+++ b/.gitignore
@@ -34,6 +34,10 @@ ai.local.json
plans/
# Beads / Dolt files (added by bd init)
+.beads/
.dolt/
*.db
.beads-credential-key
+
+# Local agent-generated config and skills
+.agents/
diff --git a/.oxfmtrc.json b/.oxfmtrc.json
index 0a01b13..69e655e 100644
--- a/.oxfmtrc.json
+++ b/.oxfmtrc.json
@@ -17,8 +17,12 @@
"ignorePatterns": [
"**/dist/**",
"**/node_modules/**",
+ "**/.agents/**",
"**/.aix/**",
"**/.astro/**",
+ "**/.beads/**",
+ "**/AGENTS.md",
+ "**/GEMINI.md",
"package-lock.json",
"packages/cli/oclif.manifest.json"
]
diff --git a/.oxlintrc.json b/.oxlintrc.json
index 8e1eaaa..1fe6445 100644
--- a/.oxlintrc.json
+++ b/.oxlintrc.json
@@ -55,6 +55,10 @@
"**/*.js",
"**/*.cjs",
"**/*.mjs",
- "**/.aix/**"
+ "**/.agents/**",
+ "**/.aix/**",
+ "**/.beads/**",
+ "**/AGENTS.md",
+ "**/GEMINI.md"
]
}
diff --git a/AGENTS.md b/AGENTS.md
index d79bf46..9a741ae 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -45,3 +45,1322 @@ git push origin vX.Y.Z
```
Pushing a `v*` tag triggers the GitHub release workflow, which publishes packages and creates the GitHub Release.
+
+
+## general
+
+## Core Principles
+
+* Readability and clarity over brevity
+* Follow existing patterns in the codebase before inventing new ones
+* Do deep research to find existing libraries (NPM, GitHub, Cargo, etc.) that solve
+ problems instead of writing code
+ * Code writing is a last resort
+* Separate formatting-only changes from functional changes
+
+## Working Habits
+
+* Be critical and thorough. Prefer truth and direct feedback over politeness
+* Look around and use existing patterns and code when possible. Look for:
+ * Similar components and use their patterns
+ * Library code you can reuse
+ * Existing dependencies from package.json or Cargo.toml that you should use
+* Always consider the developer experience:
+ * Am I placing a burden on the developer with this change?
+ * Is it as easy to use / execute / import / configure as possible?
+* When making _any_ changes:
+ * Consider the impact on other parts of the codebase
+ * What tests, documentation, etc. needs to be updated?
+ * Search for other files that should be changed after what you just did
+ * How has the context changed now that I've made this change?
+ * Should I refactor the code to introduce an abstraction to make it more
+ maintainable?
+ * Should I delete anything that's now unused?
+* Check your work after you finish a task:
+ * Did I address everything I was asked to?
+ * Run `npm run standards` (or `tsc` / `eslint` / `commitlint` / `markdownlint` /
+ `cargo lint-clippy && cargo lint-fmt` as appropriate)
+ * Test significant changes by:
+ * Running the tests
+ * Running the app and manually testing the changes (Tauri MCP/CLI or Playwright MCP/CLI)
+
+## Naming Conventions (General)
+
+* Use PascalCase for classes
+* Use camelCase for variables, instance functions, and methods
+* Use snake_case for static functions
+* Use kebab-case for file and directory names
+* Use UPPERCASE for environment variables
+* Files exporting classes: PascalCase.js (e.g., `User.js`)
+* Files exporting functions/objects: kebab-case.js (e.g., `my-function.js`)
+* Tests: `ClassTheyAreTesting.test.js`
+* Avoid magic numbers and define constants
+* When it has an acronym or initialism, use all lowercase or all caps, never mixed-case:
+ * `url` or `URL`, _never_ `Url`
+ * `id` or `ID`, _never_ `Id`. Prefer `ID` over `id` when writing docs/sentences
+ unless documenting a third-party entity or when specifically referring to a code
+ object with that exact casing (parameter, variable, etc.)
+
+## Formatting Rules
+
+### Indentation
+
+* **3 spaces** (never tabs)
+* Wrapped lines: indent one level from first line
+* Chained functions: indent one level from chain start
+
+### Braces & Structure
+
+* Opening brace at end of line (K&R style)
+* Always use braces for conditionals/loops (even single line)
+* One blank line between unrelated statements
+* One-two blank lines between functions
+
+### Spacing & Operators
+
+* Space after control structures: `if (condition)`
+* No space between function name and parenthesis: `myFunction()`
+* No space between `catch` and parentheses: `catch(error) {`
+* Space around operators (except unary: `!`, `++`, `--`)
+* Space after commas in arrays/arguments
+* Spaces inside array brackets: `[ 'item' ]` and object braces: `{ key: 'value' }`
+* Empty arrays/objects: no spaces (`[]`, `{}`)
+* Multi-line arrays/objects: always trailing comma
+
+## Control Structures
+
+* Avoid deep nesting (low cyclomatic complexity)
+* Most common case in `if` (not `else`)
+* Use positive logic over negative
+* Break complex conditions into variables/functions
+* Check error conditions early with early returns
+* Do not add defensive empty checks before operations that naturally handle empty inputs
+
+## Variable Best Practices
+
+* Declare in lowest possible scope
+* Declare at top of scope before statements
+* Initialized variables before uninitialized
+* Avoid modifying input parameters (except immediate sanitization)
+* Always sanitize user input
+* Prefer immutability (`readonly`, `as const`, `const`)
+
+## Function Documentation
+
+* Document the function purpose in JSDoc format
+* Document types or parameters if they are not obvious from the code
+* Omit JSDoc entirely when the function name already conveys its purpose
+ (e.g., do not add `/** Creates the foo */` to `createFoo()`)
+* Add JSDoc comments to enum values when the name alone doesn't convey the
+ domain-specific meaning
+
+## Comments
+
+* Only add a comment if:
+ * The code's rationale is not obvious from naming/context
+ * The comment answers "why," NOT "what" or "how"
+ * The surrounding code uses comments in a similar way
+* Do not comment on types, parameters, or usage that are clear from code or naming
+* Use ASCII in comments, never unicode symbols
+
+## File Standards
+
+* End with newline character (not blank line)
+* No Windows line endings
+* No commented-out code without reason
+* Ternary operator only for simple conditions
+
+## Front-End Development
+
+* Pay attention to the current version of the component, and use a similar pattern as
+ set by existing elements
+* Consider accessibility / a11y
+* Create reusable components rather than ad-hoc solutions
+
+## Library Usage
+
+* Use existing libraries to the fullest extent possible
+* Always verify function signatures before using
+
+## css-scss
+
+* Always use SCSS, not CSS
+* If using a component library, use the component's existing props or built-in options
+ over custom styling. Reuse appropriate CSS classes
+* If none are available, prefer pre-existing utility classes over custom styling
+* Avoid ad-hoc CSS unless absolutely necessary
+* Consider adding a custom utility class to the global SCSS if a pattern is used in
+ multiple places (e.g. text truncation, screen reader text, grid patterns)
+* Use CSS logical properties: `margin-inline-start`, not `margin-left`;
+ `text-align: start`, not `text-align: left`
+* Use CSS variables for theme-able values
+
+## ABSOLUTELY DO NOT
+
+* DO NOT use `@extend`
+* DO NOT override `line-height` to values other than `1` unless you have a very good
+ reason
+
+## SCSS API
+
+If the project auto-injects SCSS namespaces via its build config (e.g. Vite's
+`css.preprocessorOptions`), these are generally libraries and you should prefer these
+mixins/vars/functions over hard-coded values.
+
+Check the project's `vite.config.ts` or equivalent to see what is available.
+
+## Style Block Structure
+
+Vue components have **two** optional `
+
+
+```
+
+Usage:
+
+```ts
+import { MyComponentProps }, MyComponent from './MyComponent.vue';
+```
+
+## Props
+
+### TypeScript interface props (preferred)
+
+Define a TypeScript interface in the non-setup `
+
+
+```
+
+### Discriminated union props
+
+When a component has mutually-exclusive prop combinations, define separate interfaces and
+combine them with a union type. Use `never` to exclude invalid combinations:
+
+```ts
+export interface IconOnlyButtonProps extends BaseButtonProps {
+ icon: IconName;
+ label?: never;
+ ariaLabel: string; // Required when no visible label
+}
+
+export interface LabelOnlyButtonProps extends BaseButtonProps {
+ icon?: never;
+ label: string;
+ ariaLabel?: string;
+}
+
+export type ButtonProps = IconOnlyButtonProps | LabelOnlyButtonProps;
+```
+
+### `defineModel`
+
+For v-model bindings, use `defineModel` (Vue 3.4+):
+
+```ts
+const modelValue = defineModel({ default: false });
+```
+
+In the template:
+
+```vue
+
+```
+
+## Emits
+
+Unlike props and slots interfaces, emits may be defined inline:
+
+```ts
+defineEmits<{
+ 'update:selected': [value: boolean];
+ select: [event: Event];
+}>();
+```
+
+## Slots
+
+Define slot types in the non-setup `
+
+
+```
+
+### Slot props
+
+Pass CSS classes and internal state to slot consumers via `v-bind`:
+
+```vue
+
+
+
+
+
+
{{ title }}
+
+```
+
+### Checking slot existence
+
+Use `useSlots()` or `$slots` to conditionally render wrapper elements:
+
+```ts
+const slots = useSlots();
+```
+
+```vue
+
+
+
+```
+
+## VueUse
+
+Use `@vueuse/core` (and `@vueuse/components` if installed) instead of raw browser APIs.
+VueUse composables handle lifecycle cleanup automatically and are SSR-safe.
+
+| Instead of | Use |
+| --- | --- |
+| `addEventListener` / `removeEventListener` | `useEventListener()` |
+| `setTimeout` / `clearTimeout` | `useTimeoutFn()` |
+| `setInterval` / `clearInterval` | `useIntervalFn()` |
+| `new ResizeObserver()` | `useResizeObserver()` |
+| `new IntersectionObserver()` | `useIntersectionObserver()` |
+| `window.matchMedia()` | `useMediaQuery()` |
+| Manual scroll position tracking | `useScroll()` |
+| `lodash.debounce` / hand-rolled debounce | `useDebounceFn()` |
+| `getComputedStyle` / manual CSS var reads | `useCssVar()` |
+
+Other commonly used composables: `onClickOutside()`, `useElementSize()`, `useFocusTrap()`,
+`useVModel()`.
+
+## Template Refs
+
+Use `useTemplateRef` (Vue 3.5+):
+
+```ts
+const thumbnail = useTemplateRef('thumbnail');
+```
+
+## Component Composition
+
+### Dynamic element rendering
+
+Use `` to switch between element types based on props:
+
+```ts
+const elementType = computed(() => {
+ return props.href ? 'a' : 'button';
+});
+```
+
+```vue
+
+
+
+```
+
+If using a headless component library (e.g. Reka UI, Radix Vue), consider its
+`` component for root-level elements — it provides `asChild` for composability
+without extra wrapper elements in the DOM.
+
+### `inheritAttrs`
+
+When a component needs manual control over where `$attrs` are applied, disable automatic
+attribute inheritance and spread attrs explicitly:
+
+```ts
+defineOptions({ inheritAttrs: false });
+```
+
+```vue
+
+
+
+
+
+```
+
+## Exports
+
+### Component index
+
+Every component should be exported from the component index with both a named default
+export and a wildcard re-export (for types):
+
+```ts
+export * from './Button.vue';
+export { default as Button } from './Button.vue';
+```
+
+### Type exports
+
+Export all public interfaces, type aliases, and constants from the non-setup `
+
+
+
+
+
+
+```
+
+Usage:
+
+```ts
+import { MyComponentProps }, MyComponent from './MyComponent.vue';
+```
+
+## Props
+
+### TypeScript interface props (preferred)
+
+Define a TypeScript interface in the non-setup `
+
+
+```
+
+### Discriminated union props
+
+When a component has mutually-exclusive prop combinations, define separate interfaces and
+combine them with a union type. Use `never` to exclude invalid combinations:
+
+```ts
+export interface IconOnlyButtonProps extends BaseButtonProps {
+ icon: IconName;
+ label?: never;
+ ariaLabel: string; // Required when no visible label
+}
+
+export interface LabelOnlyButtonProps extends BaseButtonProps {
+ icon?: never;
+ label: string;
+ ariaLabel?: string;
+}
+
+export type ButtonProps = IconOnlyButtonProps | LabelOnlyButtonProps;
+```
+
+### `defineModel`
+
+For v-model bindings, use `defineModel` (Vue 3.4+):
+
+```ts
+const modelValue = defineModel({ default: false });
+```
+
+In the template:
+
+```vue
+
+```
+
+## Emits
+
+Unlike props and slots interfaces, emits may be defined inline:
+
+```ts
+defineEmits<{
+ 'update:selected': [value: boolean];
+ select: [event: Event];
+}>();
+```
+
+## Slots
+
+Define slot types in the non-setup `
+
+
+```
+
+### Slot props
+
+Pass CSS classes and internal state to slot consumers via `v-bind`:
+
+```vue
+
+
+
+
+
+
{{ title }}
+
+```
+
+### Checking slot existence
+
+Use `useSlots()` or `$slots` to conditionally render wrapper elements:
+
+```ts
+const slots = useSlots();
+```
+
+```vue
+
+
+
+```
+
+## VueUse
+
+Use `@vueuse/core` (and `@vueuse/components` if installed) instead of raw browser APIs.
+VueUse composables handle lifecycle cleanup automatically and are SSR-safe.
+
+| Instead of | Use |
+| --- | --- |
+| `addEventListener` / `removeEventListener` | `useEventListener()` |
+| `setTimeout` / `clearTimeout` | `useTimeoutFn()` |
+| `setInterval` / `clearInterval` | `useIntervalFn()` |
+| `new ResizeObserver()` | `useResizeObserver()` |
+| `new IntersectionObserver()` | `useIntersectionObserver()` |
+| `window.matchMedia()` | `useMediaQuery()` |
+| Manual scroll position tracking | `useScroll()` |
+| `lodash.debounce` / hand-rolled debounce | `useDebounceFn()` |
+| `getComputedStyle` / manual CSS var reads | `useCssVar()` |
+
+Other commonly used composables: `onClickOutside()`, `useElementSize()`, `useFocusTrap()`,
+`useVModel()`.
+
+## Template Refs
+
+Use `useTemplateRef` (Vue 3.5+):
+
+```ts
+const thumbnail = useTemplateRef('thumbnail');
+```
+
+## Component Composition
+
+### Dynamic element rendering
+
+Use `` to switch between element types based on props:
+
+```ts
+const elementType = computed(() => {
+ return props.href ? 'a' : 'button';
+});
+```
+
+```vue
+
+
+
+```
+
+If using a headless component library (e.g. Reka UI, Radix Vue), consider its
+`` component for root-level elements — it provides `asChild` for composability
+without extra wrapper elements in the DOM.
+
+### `inheritAttrs`
+
+When a component needs manual control over where `$attrs` are applied, disable automatic
+attribute inheritance and spread attrs explicitly:
+
+```ts
+defineOptions({ inheritAttrs: false });
+```
+
+```vue
+
+
+
+
+
+```
+
+## Exports
+
+### Component index
+
+Every component should be exported from the component index with both a named default
+export and a wildcard re-export (for types):
+
+```ts
+export * from './Button.vue';
+export { default as Button } from './Button.vue';
+```
+
+### Type exports
+
+Export all public interfaces, type aliases, and constants from the non-setup `