Use when you have a written implementation plan to execute in a separate session with review checkpoints
npx skills add EpicenterHQ/epicenter --skill "tauri"
Install specific skill from multi-skill repository
# Description
Tauri path handling, cross-platform file operations, and API usage. Use when working with file paths in Tauri frontend code, accessing filesystem APIs, or handling platform differences in desktop apps.
# SKILL.md
name: tauri
description: Tauri path handling, cross-platform file operations, and API usage. Use when working with file paths in Tauri frontend code, accessing filesystem APIs, or handling platform differences in desktop apps.
Tauri Path Handling
Context Detection
Before choosing a path API, determine your execution context:
| Context | Location | Correct API |
|---|---|---|
| Tauri frontend | apps/*/src/**/*.ts, apps/*/src/**/*.svelte |
@tauri-apps/api/path |
| Node.js/Bun backend | packages/**/*.ts, CLI tools |
Node.js path module |
Rule: If the code runs in the browser (Tauri webview), use Tauri's path APIs. If it runs in Node.js/Bun, use the Node.js path module.
Available Functions from @tauri-apps/api/path
Path Manipulation
| Function | Purpose | Example |
|---|---|---|
join(...paths) |
Join path segments with platform separator | await join(baseDir, 'workspaces', id) |
dirname(path) |
Get parent directory | await dirname('/foo/bar/file.txt') β /foo/bar |
basename(path, ext?) |
Get filename, optionally strip extension | await basename('/foo/bar.txt', '.txt') β bar |
extname(path) |
Get file extension | await extname('file.txt') β .txt |
normalize(path) |
Resolve .. and . segments |
await normalize('/foo/bar/../baz') β /foo/baz |
resolve(...paths) |
Resolve to absolute path | await resolve('relative', 'path') |
isAbsolute(path) |
Check if path is absolute | await isAbsolute('/foo') β true |
Platform Constants
| Function | Purpose | Returns |
|---|---|---|
sep() |
Platform path separator | \ on Windows, / on POSIX |
delimiter() |
Platform path delimiter | ; on Windows, : on POSIX |
Base Directories
| Function | Purpose |
|---|---|
appLocalDataDir() |
App's local data directory |
appDataDir() |
App's roaming data directory |
appConfigDir() |
App's config directory |
appCacheDir() |
App's cache directory |
appLogDir() |
App's log directory |
tempDir() |
System temp directory |
resourceDir() |
App's resource directory |
resolveResource(path) |
Resolve path relative to resources |
Patterns
Constructing Paths (Correct)
import { appLocalDataDir, dirname, join } from '@tauri-apps/api/path';
// Join path segments - handles platform separators automatically
const baseDir = await appLocalDataDir();
const filePath = await join(baseDir, 'workspaces', workspaceId, 'data.json');
// Get parent directory - cleaner than manual slicing
const parentDir = await dirname(filePath);
await mkdir(parentDir, { recursive: true });
Logging Paths (Exception)
For human-readable log output, hardcoded / is acceptable since it's not used for filesystem operations:
// OK for logging - consistent cross-platform log output
const logPath = pathSegments.join('/');
console.log(`[Persistence] Loading from ${logPath}`);
Anti-Patterns
Never: Manual String Concatenation
// BAD: Hardcoded separator breaks on Windows
const filePath = baseDir + '/' + 'workspaces' + '/' + id;
// BAD: Template literal with hardcoded separator
const filePath = `${baseDir}/workspaces/${id}`;
// GOOD: Use join()
const filePath = await join(baseDir, 'workspaces', id);
Never: Manual Parent Directory Extraction
// BAD: Manual slicing is error-prone
const parentSegments = pathSegments.slice(0, -1);
const parentDir = await join(baseDir, ...parentSegments);
// GOOD: Use dirname()
const parentDir = await dirname(filePath);
Never: Hardcoded Separators in Filesystem Operations
// BAD: Windows uses backslashes
const configPath = appDir + '/config.json';
// GOOD: Platform-agnostic
const configPath = await join(appDir, 'config.json');
Never: Assuming Path Format
// BAD: Splitting on '/' fails on Windows paths
const parts = filePath.split('/');
// GOOD: Use dirname/basename for extraction
const dir = await dirname(filePath);
const file = await basename(filePath);
Import Pattern
Always import from @tauri-apps/api/path:
import {
appLocalDataDir,
dirname,
join,
basename,
extname,
normalize,
resolve,
sep,
} from '@tauri-apps/api/path';
Note on Async
All Tauri path functions are async because they communicate with the Rust backend via IPC. Always await them:
// All path operations return Promises
const baseDir = await appLocalDataDir();
const filePath = await join(baseDir, 'file.txt');
const parent = await dirname(filePath);
const separator = await sep();
Filesystem Operations
Use @tauri-apps/plugin-fs for file operations, combined with Tauri path APIs:
import { appLocalDataDir, dirname, join } from '@tauri-apps/api/path';
import { mkdir, readFile, writeFile } from '@tauri-apps/plugin-fs';
async function saveData(segments: string[], data: Uint8Array) {
const baseDir = await appLocalDataDir();
const filePath = await join(baseDir, ...segments);
// Ensure parent directory exists
const parentDir = await dirname(filePath);
await mkdir(parentDir, { recursive: true });
await writeFile(filePath, data);
}
# Supported AI Coding Agents
This skill is compatible with the SKILL.md standard and works with all major AI coding agents:
Learn more about the SKILL.md standard and how to use these skills with your preferred AI coding agent.