본문으로 건너뛰기
cccskills
무료GitHub에 공개

architectural-integrity

Use before planning or implementing ANY feature, bug fix, refactor, or API change that touches Asyar's architecture — extension system, service layer, IPC contracts, Tauri commands, manifest contributions, or cross-layer data flow. Triggers on new features, new extension APIs, new services, bug fixes involving multiple layers, refactors of infrastructure code, adding new contribution points, and any work that could affect how built-in features or third-party extensions interact with the platform. Also triggers on any task where you need to decide which architectural layer owns the logic, whether Tier 2 extensions can use a capability, or whether a change requires a manifest/permission update. Does NOT trigger for pure CSS/styling fixes (use design-language), isolated unit tests, documentation updates, version bumps, mechanical renames, or answering informational questions about the codebase.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

Xoshbin/asyar스타 946(GitHub 946 + cccskills 0)

실행 점수 미검증

설치 방법 보기

포함된 파일(1)

  • SKILL.md29.2 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

Architectural Integrity

Asyar is a platform, not an app. Every decision — features, bug fixes, refactors — must be made from a platform-level perspective. The architecture is inspired by VS Code's extension host model: the core app is a thin, stable shell that consumes capabilities from extensions through well-defined interfaces.

Beta Phase Mindset

Asyar is in Beta. This changes everything about how you approach code:

  • Internals: break freely. Internal module boundaries, Tier 1 built-ins, frontend-only Tauri commands, launcher-private stores and schemas: no shims, no legacy hacks. If a clean design requires a breaking change, make it.
  • The third-party extension contract is protected until launcher 0.2.0. Extensions already published in the Asyar Store must keep working. This covers the manifest schema, the public asyar-sdk API, host↔extension IPC wire shapes (extensions bundle their own SDK), runtime behavior, and packaging/store formats. Never break these in place. Add the clean new contract, mark the old one deprecated (remove in 0.2.0), and keep it alive through a single boundary adapter. Full policy: .agents/rules/09-beta-compatibility-and-deprecation.md.
  • Compatibility never shapes the core. The core sees only the new, clean design. Old shapes are normalized at ingress (manifest parsing, IPC router, SDK re-export), tested with an old-format fixture, guarded by a deadline test, and deleted before 0.2.0.
  • Security/privacy outrank compatibility, and if you can't stay compatible cleanly, stop and ask the user rather than silently breaking or hacking.
  • Prioritize clean code over legacy internal contracts. If an internal interface is wrong, redesign it. Do not patch around it.

Not sure whether something is observable by a published extension? Treat it as protected and ask.


Principle 1: Process Isolation & Extension Hosts

The Pattern

All features might eventually be extended by third parties. Design every capability as if an extension will need to use it — because one will.

Asyar already implements this with its Two-Tier Extension Model:

  • Tier 1 (Built-in features) run in the privileged host context at src/built-in-features/*/. They share the main JS execution context with full Tauri API access.
  • Tier 2 (Installed extensions) follow the Separation of Headless Compute and Visual Canvas:
    • Headless Worker (role: 'worker'): Executes in an off-main-thread compute environment (e.g. Web Worker / dedicated worker host) completely decoupled from the launcher window's DOM and main renderer thread. Always-on (push subscriptions, schedules, timers, tray, RPC handlers). Heavy compute or interval polling in background workers can never drop launcher UI frames, micro-stutter the search bar, or block input handling.
    • Visual View (role: 'view'): Executes in a sandboxed visual <iframe> at the asyar-extension:// custom protocol, mounted on-demand strictly when the user navigates to an extension view and unmounted when dismissed.
    • Multi-Engine Horizon: Web Workers off the main thread today $\rightarrow$ pluggable isolated native runtimes (QuickJS / Wasm component hosts with direct Rust IPC) for high-throughput extensions tomorrow.
    • They communicate exclusively via typed IPC envelopes. A misbehaving Tier 2 extension cannot crash the host or degrade the UI event loop. See docs/explanation/extension-runtime.md.

This was a hard-learned lesson. The early implementation tried import() to load Tier 2 extensions directly into the host window. It failed in three ways: duplicate MessageBroker singletons, window.parent === window breaking postMessage routing, and lost extensionId context. The initial iframe model solved all three by isolating execution, but hit the "Everything is an Iframe" ceiling when headless workers competed with the Svelte 5 main thread. The evolved architecture enforces a strict boundary: <iframe> is exclusively for visual canvases, while headless compute lives off-main-thread in dedicated worker environments.

How to Apply This

When building a new search engine, background task, data provider, or any capability:

  1. Design a generic interface first — like SearchProvider, Extension, or ICommandService. The core app consumes data through this interface.
  2. The core app is a consumer, not an implementor. It orchestrates and renders. The actual logic lives behind the interface.
  3. Never tightly couple the main UI thread with extension execution logic. If you're writing code that only works when called directly from a Svelte component and cannot be invoked over IPC, you're creating a Tier-1-only feature. That's a design smell.

Real Asyar Examples

Good — SearchOrchestrator as a consumer: The SearchOrchestrator at src/services/search/searchOrchestrator.svelte.ts doesn't implement search. It aggregates results from the Rust search engine and from extensionManager.searchAll(query). Any extension implementing the search() method automatically contributes results. The orchestrator doesn't care where results come from.

Good — ExtensionIpcRouter as a generic dispatcher: The ExtensionIpcRouter at src/services/extension/ExtensionIpcRouter.ts routes asyar:api:{service}:{method} messages to service instances via a service registry. Adding a new service doesn't require changing the router — just register the service.

Good — sync_application_index, after the fix: The sync_application_index Tauri command at src-tauri/src/commands/applications.rs used to carry 40+ lines of diffing, indexing, and state mutation directly in the handler. It now parses its arguments and delegates: service::sync_application_index(&app, &search_state, paths). Copy this shape — the handler converts wire types, the service module owns the logic.

VS Code Parallel

VS Code's Extension Host runs in a separate process. Extensions never touch the UI thread's DOM. They communicate through a well-defined protocol. Even built-in features like Git, TypeScript language support, and Markdown preview are implemented as extensions using the same API surface as third-party extensions. This is the gold standard.


Principle 2: Declarative Contribution Points

The Pattern

Instead of hardcoding features into the UI, features register themselves through a contribution system. Internal features and third-party extensions use the exact same API to inject their capabilities.

Asyar already has this through manifest.json:

{
  "id": "org.asyar.pomodoro",
  "type": "extension",
  "background": { "main": "dist/worker.js" },
  "commands": [
    {
      "id": "start-timer",
      "name": "Start Pomodoro",
      "mode": "background",
      "icon": "▶️"
    }
  ],
  "permissions": ["notifications:send", "clipboard:write", "storage:read", "storage:write"],
  "searchable": true
}

Commands declared in the manifest are automatically indexed into the Rust search engine with the format cmd_{extensionId}_{commandId}. They appear in search results without any UI code changes. Permissions are validated at discovery time, not runtime. Platform compatibility is enforced before extension code ever loads.

How to Apply This

When adding a new system command, menu item, search source, or UI contribution:

  1. Check if a contribution point already exists. Commands go in manifest.json. Search capabilities are declared with searchable: true. Permissions are declared in the permissions array.
  2. If no contribution point exists, create one. Design it as a generic registration mechanism, not a one-off addition. The new feature should register itself the same way a third-party extension would.
  3. Never manually edit core UI components to add a feature. If you're adding an if (featureId === 'my-feature') branch in the core renderer, you're doing it wrong. The core should be feature-agnostic.

Real Asyar Examples

Good — Command index sync is manifest-driven: The syncCommandIndex() method in extensionManager.svelte.ts formats all commands as cmd_{extensionId}_{commandId} and syncs them to the Rust search index. New extensions automatically appear in search. No core UI changes needed.

Good — Extension search aggregation: Any extension with searchable: true in its manifest has its search() method called during query execution. The Calculator, Snippets, and Shortcuts extensions all contribute search results through the same mechanism. No special-casing in the search pipeline.

Good — Extension storage as a platform service: Extensions persist data via context.proxies.storage (SDK IStorageService interface). The IPC Router auto-injects the calling extensionId, so each extension's data is isolated at the SQL level (WHERE extension_id = ?). The Rust storage::extension_kv module stores all extensions' data in one shared extension_storage table in asyar_data.db. On uninstall, lifecycle.rs calls extension_kv::clear(extension_id) — no orphaned data. Permissions: storage:read / storage:write in manifest.json.

Anti-pattern to avoid — Hardcoded settings tabs: The settings page at src/routes/settings/ uses a hardcoded tab array. If a new settings section needs adding, it requires editing the core settings component. A better approach: extensions declare settings contributions in their manifest, and the settings UI renders them dynamically.

VS Code Parallel

VS Code's package.json contributes field is the canonical example. Extensions declare commands, menus, keybindings, views, settings, languages, themes, and more — all without touching VS Code's source. The core UI reads these declarations and renders accordingly. Asyar's manifest.json serves the same purpose.


Principle 3: Strict Layered Architecture

The Pattern

Backend logic must not bleed into UI presentation. Each layer has a clear responsibility:

┌─────────────────────────────────┐
│  UI Layer (Svelte components)   │  See: design-language skill
├─────────────────────────────────┤
│  Service Layer (TS services)    │  Orchestration & state ownership
├─────────────────────────────────┤
│  IPC Layer (commands.ts, IPC    │  See: review-ipc skill
│  Router, MessageBroker)         │
├─────────────────────────────────┤
│  Rust Command Layer (commands/) │  Thin wrappers only
├─────────────────────────────────┤
│  Rust Service Layer             │  See: rust-first skill
│  (search_engine/, extensions/)  │
├─────────────────────────────────┤
│  System/OS Layer                │  Hotkeys, tray, filesystem, DB
└─────────────────────────────────┘

Data flows down through these layers via well-defined interfaces. Each layer depends only on the layer directly below it.

How to Apply This

This skill focuses on the structural question: are layers properly separated, and are the interfaces between them generic enough for any consumer (built-in or third-party)?

For rules about what logic belongs in Rust vs. the frontend, see the rust-first skill. For correct Svelte 5 and Tauri 2 API usage at each layer, see the tech-versions skill.

Real Asyar Examples

Good — Extension uninstall as thin wrapper: The uninstall_extension command at src-tauri/src/commands/extensions.rs extracts state and delegates to extensions::lifecycle::uninstall(). The command layer is just plumbing — all logic lives in the service module. Any future caller (a CLI tool, a headless test, another Rust module) can reuse the same service function.

Good — Service interfaces with typed contracts: SettingsService at src/services/settings/settingsService.svelte.ts implements ISettingsService. UI components consume the interface, not the concrete class. Swapping the implementation doesn't affect consumers — the layer boundary holds.

Bad — sync_snippets_to_rust contains business logic: The sync_snippets_to_rust command at src-tauri/src/commands/snippet_commands.rs clears and rebuilds a HashMap directly in the command handler. This should delegate to a snippets::service::sync() function. The command layer should never own transformation logic.

Bad — UI components calling Tauri commands directly: When a Svelte component calls commands.checkSnippetPermission() directly instead of routing through a service, it bypasses the service layer and tightly couples the UI to the IPC contract.

VS Code Parallel

VS Code's architecture has a strict process boundary: the renderer process (UI), the main process (orchestration), and extension host processes (logic). The renderer never runs extension code. The main process mediates all communication. This process boundary enforces layer separation at the OS level — you literally cannot violate it.


Principle 4: Anti-Patterns to Reject

Never Pass Raw UI Components to Extensions

Early extensible platforms tried passing DOM access or UI framework components directly to extensions. This tightly couples extensions to the host's internal framework and breaks constantly when the host upgrades.

Asyar's correct approach: Tier 2 extensions get sandboxed iframes for visual presentation (role: 'view') and off-main-thread worker contexts for headless compute (role: 'worker'), communicating through typed IPC. They cannot touch the host's DOM or internal Svelte components. This is exactly how VS Code's Webview and Extension Host APIs work — extension views provide HTML content rendered in a sandboxed frame, while extension logic runs off the UI thread without accessing the host renderer DOM.

For data-driven UI (like lists and trees): Use declarative data structures. The extension provides data (title, icon, description, actions); the host renders it in the standard UI. This is the pattern behind ExtensionResult[] returned from search() — the extension describes results, the host renders them in ResultsList.

For the specific design tokens, components, and styling rules that apply to both host and extension UI, see the design-language skill.

Never Fix Symptoms — Fix Infrastructure

If a bug's root cause is a flaw in the infrastructure design, do not apply a localized patch. Tear down the bad infrastructure and rebuild it cleanly.

Example: If the search system has a bug because extension results aren't properly ranked, don't add a special-case sort hack in the UI. Fix the ranking logic in the Rust search_engine or in SearchOrchestrator's aggregation. If the ranking interface is fundamentally wrong, redesign it.

Example: If an IPC message isn't reaching an extension, don't add a retry loop in the component. Trace the message through MessageBroker → ExtensionIpcRouter → permission gate → service dispatch. Find the actual failure point and fix the contract.

Since Asyar is in Beta, you have full permission to make breaking changes to internals to fix root causes. There is no excuse for symptom patching. If the root-cause fix changes the protected third-party extension contract, redesign it cleanly and keep the old contract working as a deprecated boundary adapter until 0.2.0 (see Beta Phase Mindset).

Never Hardcode What Should Be Registered

If you find yourself writing a switch statement or if/else chain that checks for specific extension IDs, feature names, or command types — stop. You're hardcoding what should be dynamically registered.

Case study — the service registry. Until early 2026, the registry mapped PascalCase class names to service instances:

this.serviceRegistry = {
  LogService: logService,
  NotificationService: new NotificationService(),
  ClipboardHistoryService: ClipboardHistoryService.getInstance(),
  StorageService: extensionStorageService,
  // ... hardcoded list
};

Two problems: the class name leaked into the wire contract (renaming LogService silently broke every extension), and the list was unchecked — nothing stopped a future contributor from adding 'MyNewService' and recreating the anti-pattern.

The fix is a two-layer mechanical guard:

  1. asyar-sdk/src/ipc/namespaces.ts is the single source of truth. The NAMESPACES readonly array lists every valid wire namespace; the Namespace union type is derived from it.
  2. defineServiceRegistry() at asyar-launcher/src/services/extension/defineServiceRegistry.ts is a typed identity function whose parameter extends Partial<Record<Namespace, unknown>>. Passing a non-canonical key is a compile error. The registry itself is composed in asyar-launcher/src/services/extension/buildServiceRegistry.ts.
return defineServiceRegistry({
  log: logService, // canonical lowercase key IS the wire namespace
  clipboard: clipboardHistoryService, // module singleton — see service-singletons
  commands: commandService,
  actions: actionService,
  // MyNewService: x,                    // compile error
});

The key IS the wire namespace (asyar:api:<namespace>:<method>). Renaming the backing class never breaks the wire. Adding a new namespace is a single edit to NAMESPACES followed by compile errors pointing at every place that needs updating.

Never Introduce Capabilities Blindly (Search First, Maintain Single Ownership)

Before adding any capability, action, IPC route, shortcut, event listener, or state store (whether explicitly requested or added as a companion enhancement):

  1. Repository-Wide Discovery Before Creation: Always search the entire codebase (grep_search for related keywords, handlers, or IPC namespaces). Never assume a capability or registration doesn't exist just because it is absent from the specific file you are editing.
  2. Single Layer of Ownership: Every capability must have exactly one canonical owner. Do not split or duplicate registrations across different layers (e.g. host core vs. extension loader runtime).
  3. No Unaudited Companion Features: If you proactively introduce companion features or UX improvements alongside a user request, you must apply the exact same discovery rigor to ensure you are not duplicating existing logic.

Case study — Duplicate extension configuration actions:

  • The Mistake: When adding the built-in "View Extension Commands" action to actionService.svelte.ts, an agent proactively added a companion "Configure Extension Settings" action (commands.showSettingsWindow('extensions', extensionId)). The agent did not search the rest of the repository and missed that ExtensionLoader.ts was already dynamically auto-registering "Extension Preferences" (act_${extensionId}_open_preferences) with the exact same execution handler.
  • The Consequence: Highlighting any extension with preferences in the launcher produced two duplicate configuration actions in the ⌘K Action Panel.
  • The Fix & Guard:
    • Host-level platform actions (settings, deeplinks, command lists) belong exclusively in ActionService as single sources of truth with standard shortcuts (⌘ ⇧ ,).
    • Extensions and built-ins register actions in code (actionService.registerAction); there are no manifest-declared actions.

Shortcut & Action ID Collision Discipline

When introducing or modifying keyboard shortcuts or action identifiers:

  1. Conflict Verification: Always verify that the proposed key combination (e.g. Super+Shift+,, Super+Shift+E) is not already bound in actionService.svelte.ts or consumed by launcherKeyboard.ts.
  2. Preserve Native Text Editing: In views where a search bar or text input is active, never bind native text editing shortcuts (Cmd+Backspace, Option+Backspace, Cmd+A, Cmd+C, Cmd+V, Cmd+X, Cmd+Z) to list actions or item deletion.
  3. Destructive Actions in ⌘K: Destructive item operations (Delete, Move to Trash, Uninstall) belong in the ⌘K Action Panel with destructive: true and appropriate confirmation dialogs, never bound to Cmd+Backspace / Super+Backspace.
  4. Platform Neutrality: Use Super for macOS Command and Ctrl for Windows/Linux.
  5. No Unrequested Companion Features ("Propose, Don't Presume"): If you identify a high-value companion action, command, or shortcut while implementing a task, mention and propose it to the user with its rationale first rather than silently adding extra unrequested features.

Never Let IPC Boundaries Leak Implementation Details

When designing any cross-boundary data flow (Rust↔TS, Host↔Extension, Service↔Component), ensure the contract is clean serializable data. No framework proxies, no class instances, no callbacks that won't survive serialization. If something can't cross a postMessage or invoke() boundary cleanly, the interface is wrong — redesign it.

For auditing specific IPC contracts, permission gate coverage, and type string consistency, see the review-ipc skill.


Principle 5: Centralized Gate & Policy Engine (Fail-Closed Egress & Authorization)

The Pattern

Privacy and data security in Asyar are fail-closed by default. No private user data, telemetry, or privileged cloud requests ever leave the device unless explicitly authorized by authentication, entitlement, and user consent.

  • Rust Core is the Policy Brain: All policy evaluations and authorization rules are defined and enforced in native Rust (crate::auth::policy::Gate).
  • Typed Ability Enum: All privileged operations are represented by typed variants (Ability::CloudSyncEgress, Ability::AiCloudModels, Ability::AiConversationSync, Ability::TelemetryCrashReport, Ability::TelemetryUsageShare). String-matching checks are strictly forbidden for core abilities.
  • Fail-Closed by Default: If an ability is evaluated against an unauthenticated context or missing entitlement, Gate::evaluate rejects immediately with Err(PolicyError::Unauthenticated) or Err(PolicyError::MissingEntitlement).
  • Frontend Svelte 5 GateService: The frontend UI and services consume gate.allows(ability), gate.denies(ability), and gate.gate(ability).
  • Zero Legacy Fallbacks: Never implement legacy fallbacks that assume signed-out users are "free tier unrestricted" for outbound network egress. Signed-out state is completely inert.

Principle 6: First-Class Platform Primitives & Service Exposure

The Pattern

Built-in features in Asyar (such as Calculator, Clipboard History, Snippets, Notes, Aliases, Window Management, and System) are first-class platform primitives, not pseudo-extensions. They do not incur dynamic manifest parsing or IPC closure-stripping side-tables (inlineActions). They consist of two distinct layers:

  1. Platform Service Layer: Rust engine, background SQLite store, system event watchers, and IPC service handlers registered in buildServiceRegistry.ts.
  2. Bundled UI Layer: Svelte views, command palette entries, search bar interceptors/accessories, ⌘K actions, and deeplink routes.

Invariants for Built-in Features

  • Statically Compiled Primitives: Built-ins are hardwired into the platform with zero runtime manifest parsing overhead or cold-boot disk crawling. Third-party extensions remain the sole consumers of dynamic manifests.
  • Direct, Typed Search Contributions: Built-in providers (e.g. Calculator) contribute directly to search results without closure stripping.
  • Direct Reactive Settings Gate: Disabling an optional built-in feature via Settings uses a direct reactive gate (if (!settings.features[id].enabled) or settings toggle), cleanly suppressing its UI commands, accessories, and search suggestions without unregistering, killing, or clearing the underlying platform service.
  • Core Infrastructure is Locked: Only essential recovery infrastructure (system and settings) is non-disableable.
  • Resilient Platform Services: Platform services (files:search, screen:capture, calculator:evaluate, notes:read) must remain registered in ServiceRegistry (buildServiceRegistry) so permission-authorized Tier 2 extensions can consume them uninterrupted regardless of whether the bundled UI is enabled or disabled.
  • Ambient Search Interceptors vs Command/View Features:
    • Destination features (Notes, Snippets, Runs, File Search) expose commands or views that Tier 2 extensions can replace 1:1.
    • Ambient search interceptors (Calculator) evaluate queries directly in the root search bar. Built-in interceptors have access to priority: 'top' (which is intentionally stripped for third-party extensions in searchOrchestrator to prevent search hijacking) and specialized hero cards (CalcResultCard.svelte). Disabling Calculator is primarily designed for users who want to disable inline math evaluation and keep the search bar clean; third-party extensions contribute calculation results via standard fuzzy ranking (type: 'result').

Principle 7: Strict Separation of Presentation Lifecycle and Daemon Compute

The Pattern

A desktop launcher operates on two fundamentally divergent timescales:

  1. The Ephemeral Window Presentation Lifecycle (Milliseconds):
    • Triggered by hotkey (Cmd+Space / Option+Space).
    • Must achieve sub-16ms first-frame render (60/120 FPS), instantaneous query typing, zero-IPC instant filtering, and sub-10ms dismissal (hideWindow()).
  2. The Durable Extension Daemon Lifecycle (Minutes to Days):
    • Background extensions manage long-lived states: WebSocket connections, filesystem watchers, background timers, clipboard history collectors, and sync engines.

Invariants

  • Zero-Cost Reveal Invariant: Revealing, typing in, and dismissing the launcher UI must never await or be blocked by extension daemon lifecycle events (mounting, syncing, network reconnection, command indexing). Hotkey invocation, window dismissal, and state reset touch only UI presentation concerns (query reset, navigation stack shrink, focus). Extension command indexing and worker restoration are non-blocking, deferred to idle periods (runWhenIdle), ensuring the launcher window is immediately interactive on cold boot.
  • Independent Daemon Lifespan: Background extensions are long-lived daemons managed by the runtime. Hiding or resetting the search window must never destroy, suspend, or corrupt background worker state. Workers, long-running background timers, WebSocket connections, and native background watchers continue executing reliably even when the launcher window remains hidden for hours.

Session Start Protocol

At the start of every conversation:

  1. Read the task. Understand what the user is asking for.
  2. Identify which architectural layers are involved. Refer to the layer diagram above.
  3. Check for architectural violations in the area you'll touch. Before writing new code on top of bad infrastructure, flag it.
  4. Only then proceed with implementation.

If the task is purely informational (explaining code, answering a question), the Architectural Impact summary can be brief. But it must exist. Even "This is a read-only investigation — no architectural changes proposed" counts.


Quick Reference: Decision Checklist

Before writing any code, verify:

  • New capability accessible through a generic interface (not hardcoded to one consumer)?
  • Tier 2 extensions could use this through the existing IPC/manifest system?
  • Optional built-in features declare "lifecycle": { "disableable": true } and preserve underlying platform services when disabled?
  • Tauri commands are thin wrappers delegating to service modules?
  • Could a published extension observe this change (manifest, SDK API, IPC wire shape, runtime behavior)? If yes: new contract added beside the old, old marked deprecated (remove in 0.2.0), compat confined to one boundary adapter with a fixture test and deadline guard. If no: no shims or legacy wrappers at all.
  • New UI contributions registered declaratively (manifest/registry), not hardcoded?
  • Cross-boundary data is clean serializable types (no Proxies, no class instances)?
  • Repository-wide search conducted to ensure no duplicate capabilities or split-layer registrations exist?
  • Root cause addressed, not symptoms patched?

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

Use when building, modifying, or fixing any frontend UI in the Asyar launcher — new components, new views, layout changes, styling decisions, new built-in features, visual bug fixes, and anything in settings or onboarding. Answers "what do I use here?" for fonts, colour, typography, spacing, motion, components, and layout.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

Xoshbin/asyar9462026년 10월 27일 업데이트

Reference for the Asyar monorepo structure, SDK workspace linking, lockfile discipline, CI workflows, and release flow. Use this skill whenever working on anything related to pnpm workspace setup, the asyar-sdk dependency, lockfile errors, SDK or launcher version bumps, CI configuration, release workflow, or questions about how local dev differs from CI. Also triggers for "how does the workspace work", "how do I update the SDK version", "where do I run pnpm install", or any confusion about the monorepo layout.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

Xoshbin/asyar9462026년 10월 27일 업데이트

Never hand-edit or hand-copy generated content. Use when touching permissions.rs, error.rs, AppError/SearchError variants, runtimes/catalog.fallback.json, any `#[derive(specta::Type)]` struct, any file with an AUTO-GENERATED banner (kinds.ts, gatedPermissions.ts, knownRuntimes.ts, bindings.ts, emoji data), or whenever you are about to write a TypeScript list/type that mirrors a Rust source.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

Xoshbin/asyar9462026년 10월 27일 업데이트

Audit IPC message contracts between extensions and the Asyar host. Use when adding a new SDK service, adding a new proxy method, changing a postMessage type string, or reviewing permission gate coverage.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

Xoshbin/asyar9462026년 10월 27일 업데이트

tdd

무료

Use when implementing any new feature or fixing any bug in this project — both Rust (src-tauri) and TypeScript/Svelte 5 (src). Triggers on phrases like "add X", "fix Y", "implement Z", "change how W works".

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

Xoshbin/asyar9462026년 10월 27일 업데이트

Xoshbin의 스킬 모두 보기

이 스킬의 문제 신고