epicenterhq-tauri
SKILL.md
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);
}