Files
fullstack-starter/apps/desktop/AGENTS.md
imbytecat e41c4e4515 docs: 更新 AGENTS.md 文档结构和内容
- 新增根目录 AGENTS.md 作为 monorepo 总览
- 移动 desktop AGENTS.md 从 src-tauri/ 到 apps/desktop/
- 修正 server AGENTS.md 目录结构 (src/server/api/ 而非 src/orpc/)
- 明确 desktop 为纯 Tauri 壳子,无前端代码,通过 sidecar 加载 server
2026-02-07 03:29:51 +08:00

4.5 KiB

AGENTS.md - Desktop App Guidelines

Tauri v2 desktop shell - a lightweight wrapper that loads the server app via sidecar.

Architecture

  • Type: Tauri v2 desktop application (shell only)
  • Design: Tauri provides native desktop APIs; all web logic handled by sidecar
  • Sidecar: The compiled server binary runs as a child process
  • Dev mode: Connects to localhost:3000 (requires server dev running)
  • Prod mode: Automatically starts sidecar binary

This app has NO frontend src - it loads the server app entirely.

Commands

# Development (from apps/desktop/)
bun dev                    # Copy sidecar + start Tauri dev

# Build
bun build                  # Copy sidecar + build Tauri installer

# Rust Commands (from src-tauri/)
cargo check                # Compile check
cargo clippy               # Linter
cargo fmt                  # Formatter
cargo test                 # Run tests
cargo test test_name -- --nocapture  # Single test with output

Directory Structure

apps/desktop/
├── src-tauri/             # Rust Tauri code
│   ├── src/
│   │   ├── main.rs        # Entry point (calls lib::run)
│   │   ├── lib.rs         # Core app logic (plugins, commands, state)
│   │   ├── commands/
│   │   │   └── mod.rs     # Native desktop commands
│   │   └── sidecar.rs     # Sidecar process management
│   ├── binaries/          # Sidecar binaries (copied from server build)
│   ├── capabilities/      # Tauri v2 permission config
│   ├── icons/             # App icons
│   ├── Cargo.toml         # Rust dependencies
│   └── tauri.conf.json    # Tauri configuration
├── copy.ts                # Script to copy server binary to binaries/
├── package.json
└── tsconfig.json

Development Workflow

  1. Start server dev first: cd ../server && bun dev
  2. Start Tauri: bun dev (from apps/desktop/)
  3. Tauri connects to localhost:3000 with HMR support

Rust Code Style

Formatting

  • Indent: 4 spaces
  • Line width: 100 chars
  • Run cargo fmt before commit

Naming

Type Convention Example
Functions/variables snake_case find_available_port
Types/structs/enums PascalCase SidecarProcess
Constants SCREAMING_SNAKE DEFAULT_PORT

Imports

// Order: std → external crates → internal modules (separated by blank lines)
use std::sync::Mutex;

use tauri::Manager;
use tauri_plugin_shell::ShellExt;

use crate::sidecar::SidecarProcess;

Error Handling

// Use expect() with Chinese error messages
let sidecar = app_handle
    .shell()
    .sidecar("server")
    .expect("无法找到 server sidecar");

// Log with emoji for clear feedback
println!("✓ Sidecar 启动成功!");
eprintln!("✗ Sidecar 启动失败");

Async Code

// Use Tauri's async runtime for spawning
tauri::async_runtime::spawn(async move {
    let port = find_available_port(3000).await;
    // ...
});

Tauri Patterns

Command Definition

#[tauri::command]
fn greet(name: &str) -> String {
    format!("Hello, {}!", name)
}

// Register in Builder
.invoke_handler(tauri::generate_handler![commands::greet])

State Management

struct SidecarProcess(Mutex<Option<CommandChild>>);

// Register state
app.manage(SidecarProcess(Mutex::new(None)));

// Access state
if let Some(state) = app_handle.try_state::<SidecarProcess>() {
    *state.0.lock().unwrap() = Some(child);
}

Sidecar Lifecycle

// Start sidecar with environment
let sidecar = app_handle
    .shell()
    .sidecar("server")
    .expect("无法找到 server sidecar")
    .env("PORT", port.to_string());

// Cleanup on exit
match event {
    tauri::RunEvent::ExitRequested { .. } | tauri::RunEvent::Exit => {
        if let Some(child) = process.take() {
            let _ = child.kill();
        }
    }
    _ => {}
}

Critical Rules

DO:

  • Run cargo fmt and cargo clippy before commit
  • Use expect("中文消息") instead of unwrap()
  • Always cleanup sidecar on app exit
  • Declare sidecar in tauri.conf.jsonbundle.externalBin

DON'T:

  • Edit gen/schemas/ (auto-generated)
  • Use unwrap() in production code without context
  • Block the async runtime (use spawn_blocking)

Pre-commit Checklist

  • cargo fmt - formatting
  • cargo clippy - linting
  • cargo check - compiles
  • cargo test - tests pass
  • Tauri app starts and exits cleanly