Desenvolvimento Tauri com Claude Code: Vite, comandos Rust e permissoes
Guia pratico de Tauri v2 com Claude Code: Vite, Rust commands, invoke, permissoes de arquivos, testes e review.
Tauri transforma uma UI web em app desktop para Windows, macOS e Linux. A tela pode continuar em React, Svelte ou outro stack frontend, enquanto as operacoes nativas ficam no Rust. Essa divisao combina bem com Claude Code porque permite pedir tarefas pequenas: uma tela, um Rust command, uma capability, um teste ou um ajuste de build.
Este guia usa Tauri v2 e um app simples de notas locais. Vamos cobrir quando escolher Tauri, setup com Vite + React ou Svelte, comandos Rust, chamadas invoke no frontend, permissoes de arquivos, comandos de build e teste, prompts para revisar permissoes, casos de uso reais e armadilhas comuns.
As referencias oficiais usadas foram Tauri Create a Project, Calling Rust from the Frontend, Tauri Capabilities, File System plugin, Vite Getting Started, Cargo test e Claude Code setup. Para base de Rust, leia Rust com Claude Code. Para comparar com Electron, veja Electron desktop app development.
Quando escolher Tauri
Tauri faz sentido quando voce precisa de um aplicativo local, mas quer manter a produtividade de uma UI web. Exemplos: notas privadas, conversor CSV interno, visualizador de logs, ferramenta para desenvolvedores, app offline de campo, inventario ou checklist.
Nao escolha Tauri apenas porque ele parece mais leve. Voce tambem assume toolchain Rust, empacotamento, assinatura, instaladores, diferencas entre sistemas operacionais, identificador do app e estrategia de atualizacao. Se o produto e basicamente uma web app com login e APIs remotas, uma web app normal ou PWA pode ser mais simples.
Um bom primeiro prompt para Claude Code:
Vamos criar um app Tauri v2 de notas locais.
Nao implemente ainda.
Divida o trabalho em React UI, Rust commands, capabilities e build/test.
O acesso a arquivos deve ficar dentro do diretorio app data.
Nao proponha leitura ou escrita de caminhos arbitrarios.
Assim o modelo discute a fronteira de seguranca antes de criar permissoes amplas.
Fronteira de arquitetura
No Tauri, o frontend nao deve tocar diretamente o sistema operacional. Ele chama comandos Rust com invoke; Rust valida a entrada, acessa o recurso local e retorna um resultado tipado.
flowchart LR
UI["React ou Svelte UI"] --> Invoke["invoke from @tauri-apps/api/core"]
Invoke --> Command["Rust command"]
Command --> Guard["allowlist e validacao de caminho"]
Guard --> AppData["diretorio app data"]
Command --> Result["resultado tipado"]
Result --> UI
Capability["Tauri capability"] --> UI
O ponto que mais causa erro e: capabilities limitam APIs e plugins acessiveis pelo frontend, mas nao tornam seus comandos Rust automaticamente seguros. Se um command aceita qualquer caminho e escreve nele, a app continua perigosa. Capability e validacao Rust precisam ser revisadas juntas.
Setup com React ou Svelte
Para um projeto novo, use o caminho oficial create-tauri-app. Escolha React ou Svelte e TypeScript.
npm create tauri-app@latest taskdesk
cd taskdesk
npm install
npm run tauri dev
Se ja existe uma app Vite, prepare o frontend e inicialize Tauri depois. A documentacao do Vite mostra npm create vite@latest e, atualmente, exige Node.js 20.19+ ou 22.12+.
node --version
npm create vite@latest taskdesk -- --template react-ts
cd taskdesk
npm install
npm install -D @tauri-apps/cli@latest
npm install @tauri-apps/api@latest
npx tauri init
npx tauri dev
Para Svelte, troque apenas o template:
npm create vite@latest taskdesk -- --template svelte-ts
Depois do setup, peca para Claude Code ler antes de editar:
Leia package.json, tauri.conf.json e src-tauri/src/lib.rs.
Resuma a estrutura atual do projeto e os scripts.
Nao modifique arquivos ainda.
Templates mudam. Ler o projeto gerado reduz erros baseados em exemplos antigos.
Configuracao Tauri minima
tauri.conf.json conecta servidor Vite, build frontend, janela e capability.
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "TaskDesk",
"version": "0.1.0",
"identifier": "com.example.taskdesk",
"build": {
"beforeDevCommand": "npm run dev",
"devUrl": "http://localhost:5173",
"beforeBuildCommand": "npm run build",
"frontendDist": "../dist"
},
"app": {
"windows": [
{
"title": "TaskDesk",
"width": 1000,
"height": 700
}
],
"security": {
"capabilities": ["main-capability"]
}
},
"bundle": {
"active": true,
"targets": "all"
}
}
Revise identifier, devUrl e frontendDist. Esses campos costumam gerar debug inutil quando ficam desalinhados.
Comandos Rust
O app de notas precisa ler, escrever e listar. O exemplo foca na validacao: rejeitar caminho absoluto, .. e saida do app data.
// src-tauri/src/note_commands.rs
use serde::Serialize;
use std::{
fs,
path::{Component, Path, PathBuf},
};
use tauri::{AppHandle, Manager};
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct NoteFile {
name: String,
path: String,
bytes: u64,
is_dir: bool,
}
fn reject_unsafe_relative(path: &Path) -> Result<(), String> {
for component in path.components() {
match component {
Component::Normal(_) | Component::CurDir => {}
_ => return Err("use a relative path inside app data".to_string()),
}
}
Ok(())
}
fn app_data_root(app: &AppHandle) -> Result<PathBuf, String> {
let root = app
.path()
.app_data_dir()
.map_err(|error| format!("failed to get app data dir: {error}"))?;
fs::create_dir_all(&root).map_err(|error| format!("failed to create app data dir: {error}"))?;
root.canonicalize()
.map_err(|error| format!("failed to resolve app data dir: {error}"))
}
fn existing_path(app: &AppHandle, relative: &str) -> Result<PathBuf, String> {
let root = app_data_root(app)?;
let requested = Path::new(relative);
reject_unsafe_relative(requested)?;
let full = root
.join(requested)
.canonicalize()
.map_err(|error| format!("path does not exist: {error}"))?;
if !full.starts_with(&root) {
return Err("path escapes app data".to_string());
}
Ok(full)
}
#[tauri::command]
pub fn read_note(app: AppHandle, path: String) -> Result<String, String> {
let safe_path = existing_path(&app, &path)?;
fs::read_to_string(safe_path).map_err(|error| format!("failed to read note: {error}"))
}
Registre no lib.rs:
// src-tauri/src/lib.rs
mod note_commands;
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![
note_commands::read_note
])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
Invoke no TypeScript
Crie um wrapper pequeno para centralizar nomes e payloads.
// src/lib/notesApi.ts
import { invoke } from "@tauri-apps/api/core";
export type NoteFile = {
name: string;
path: string;
bytes: number;
isDir: boolean;
};
export const notesApi = {
read(path: string) {
return invoke<string>("read_note", { path });
},
write(path: string, content: string) {
return invoke<void>("write_note", { path, content });
},
list(dir = ".") {
return invoke<NoteFile[]>("list_notes", { dir });
},
};
Um componente React minimo:
import { useState } from "react";
import { notesApi } from "./lib/notesApi";
export default function App() {
const [content, setContent] = useState("");
const [message, setMessage] = useState("Ready");
async function saveNote() {
await notesApi.write("daily-note.txt", content);
setMessage("Saved");
}
return (
<main>
<textarea value={content} onChange={(event) => setContent(event.target.value)} />
<button onClick={saveNote}>Save</button>
<p>{message}</p>
</main>
);
}
Permissoes e capabilities
Se o frontend usa File System plugin diretamente, limite a capability:
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "main-capability",
"description": "Main window permissions for TaskDesk.",
"windows": ["main"],
"permissions": [
"core:default",
"fs:default",
"fs:allow-app-read-recursive",
"fs:allow-app-write-recursive"
]
}
Neste artigo, arquivos passam por comandos Rust. Entao nao ha motivo para dar ao frontend permissoes amplas sobre Downloads ou Documents. Prompt de review:
Apenas revise, nao edite.
Inspecione src-tauri/capabilities e src-tauri/src/note_commands.rs.
Liste cada API exposta ao frontend e cada Rust command.
Explique quais caminhos de arquivo cada um pode tocar.
Marque caminhos absolutos, .., wildcards amplos e escrita fora de app data.
Sugira o menor conjunto de permissoes que mantem a funcionalidade.
Build, testes e casos reais
Separe os checks:
npm run build
cd src-tauri
cargo test
cd ..
npm run tauri build
npm run build valida Vite, cargo test valida Rust e npm run tauri build valida empacotamento desktop. Regras de caminho podem ser testadas em Rust puro:
#[cfg(test)]
mod tests {
use super::reject_unsafe_relative;
use std::path::Path;
#[test]
fn rejects_parent_directory() {
assert!(reject_unsafe_relative(Path::new("../secret.txt")).is_err());
}
}
Tres casos fortes sao notas locais, conversor CSV/Markdown e visualizador de logs. Um quarto e app offline de inventario, check-in ou inspecao. As armadilhas principais sao confundir capability com seguranca do Rust command, pedir a app inteira de uma vez ao Claude Code, levar configuracao de desenvolvimento para producao, testar em um unico OS e abrir permissoes de arquivo alem do necessario.
CTA e resultado testado
Para transformar isso em rotina, veja ClaudeCodeLab products and templates ou Claude Code training and consultation. Em equipes, a revisao precisa incluir CLAUDE.md, prompts de review, regras de capability e comandos de verificacao.
No fluxo testado para este artigo, a ordem mais estavel foi definir primeiro a fronteira de caminhos no Rust, depois criar o wrapper TypeScript de invoke e por ultimo revisar capabilities. Comecar pela UI parece rapido, mas aumenta retrabalho quando armazenamento e permissoes ficam claros.
PDF grátis: cheatsheet do Claude Code
Informe seu e-mail e baixe uma página com comandos, hábitos de revisão e workflows seguros.
Cuidamos dos seus dados e não enviamos spam.
Sobre o autor
Masa
Engenheiro focado em workflows práticos com Claude Code.
Artigos relacionados
Workflow Obsidian para CLAUDE.md com Claude Code
Transforme notas de trabalho do Obsidian em notas operacionais CLAUDE.md para preservar contexto.
Claude Code Revenue CTA Routing: artigos para PDF, Gumroad e consultoria
Um fluxo com Claude Code para levar leitores ao PDF grátis, Gumroad ou consultoria conforme intenção.
Regras de handoff para equipes com Claude Code: evidências, permissões, rollback e receita
Formato prático para entregar trabalho do Claude Code com prova, permissões, rollback, PDF grátis, Gumroad e consultoria.