Command Handlers
Relevant source files
The following files were used as context for generating this wiki page:
This document details the Tauri command handlers that form the bridge between the Vue.js frontend and the Rust backend. Command handlers are Rust functions marked with the #[tauri::command] attribute that can be invoked from the frontend via the Tauri IPC bridge. These handlers manage workspace loading, board and card operations, file system watching, and application configuration.
For information about the main entry point and menu system, see 6.1. For details on the underlying workspace operations that commands invoke, see 6.3.
Command Registration
All command handlers are registered in main.rs using Tauri's generate_handler! macro. The registration occurs during application setup and makes these functions callable from the frontend via invoke().
Registration in main.rs
The Tauri application builder registers all command handlers in a single invocation:
This registration makes the commands available to the frontend through the @tauri-apps/api package. The frontend can invoke commands using invoke('command_name', { param: value }).
Command Module Structure
Command handlers are imported from the backend::commands module:
The backend is organized into specialized command modules that handle different domains of functionality. This modular structure keeps the main entry point lightweight while organizing commands by their area of responsibility.
Sources:
Command Categories
The command handlers are organized into five functional categories, each managing a specific aspect of the application.
Command Category Overview
Sources:
Workspace Commands
Workspace commands manage the loading, saving, and synchronization of the entire workspace tree. These are the primary commands that establish the working context for the application.
Workspace Command Functions
| Command | Purpose | Parameters | Returns |
|---|---|---|---|
load_workspace | Loads all boards and cards from a board root | root_path: String | WorkspaceSnapshot |
save_workspace_boards | Saves multiple board files atomically | root_path: Stringwrites: Vec<FileWrite> | WorkspaceSnapshot |
apply_workspace_snapshot | Applies a complete workspace state (for undo/redo) | snapshot: WorkspaceSnapshot | WorkspaceSnapshot |
load_app_config | Loads application configuration | none | AppConfig |
save_app_config | Saves application configuration | config: AppConfig | AppConfig |
sync_known_board_tree | Discovers and persists sub-boards | root_path: String | WorkspaceSnapshot |
Workspace Loading Flow
The load_workspace command is the entry point for establishing a workspace session. It takes a board root path (pointing to a TODO/ directory), discovers all nested sub-boards, reads board and card markdown files, and returns a WorkspaceSnapshot containing raw file content.
Snapshot Application Flow
The apply_workspace_snapshot command supports undo/redo by applying a previously captured workspace state:
Sources:
Card Commands
Card commands handle the creation, modification, and deletion of individual card files within the workspace.
Card Command Functions
| Command | Purpose | Parameters | Returns |
|---|---|---|---|
create_card_in_board | Creates a new card file and adds it to a board | root_path: Stringboard_path: Stringcolumn_slug: Stringtitle: String | WorkspaceSnapshot |
save_card_file | Saves card markdown content | root_path: Stringcard_path: Stringmarkdown: String | WorkspaceSnapshot |
rename_card | Renames a card file and updates references | root_path: Stringold_card_path: Stringnew_title: String | WorkspaceSnapshot |
delete_card_file | Deletes a card file | root_path: Stringcard_path: String | WorkspaceSnapshot |
Card Creation Flow
Card commands use the commands/support.rs module for shared logic like board path resolution and card slug generation. Each command returns a fresh WorkspaceSnapshot after successfully persisting changes, ensuring the frontend has an up-to-date view of the workspace.
Sources:
Board Commands
Board commands manage board file creation, modification, and deletion, including handling the board's TODO/todo.md file and its associated directory structure.
Board Command Functions
| Command | Purpose | Parameters | Returns |
|---|---|---|---|
create_board | Creates a new board with TODO/ structure | parent_path: Stringboard_name: Stringtitle: String | WorkspaceSnapshot |
save_board_file | Saves board markdown content | root_path: Stringboard_path: Stringmarkdown: String | WorkspaceSnapshot |
rename_board | Renames a board (title only, path-based identity) | root_path: Stringboard_path: Stringnew_title: String | WorkspaceSnapshot |
delete_board | Deletes a board and its directory | root_path: Stringboard_path: String | WorkspaceSnapshot |
Board Creation Structure
When create_board is invoked, it creates a complete board directory structure:
parent_path/
└── board_name/
└── TODO/
├── todo.md (board file with title)
├── cards/ (directory for card files)
└── README.md (board notes)The command creates all necessary directories and files atomically, ensuring a valid board structure exists before returning the updated workspace snapshot.
Board Save Flow
Board commands enforce path validation through the commands/support.rs module. Board writes must target a TODO/todo.md file to prevent accidental writes to card files or other locations.
Sources:
File System Watcher Commands
Watcher commands manage the file system monitoring that enables real-time synchronization when external tools modify the workspace.
Watcher Command Functions
| Command | Purpose | Parameters | Returns |
|---|---|---|---|
watch_workspace | Starts watching a workspace for file changes | root_path: String | Result<(), String> |
unwatch_workspace | Stops watching the current workspace | none | Result<(), String> |
Watcher State Management
The file system watcher uses managed state to maintain a single active watcher instance:
The WorkspaceWatcherState is a Tauri-managed state that stores the active file watcher. This ensures only one watcher runs at a time and allows clean shutdown when switching workspaces or closing the folder.
Watcher Event Flow
When file changes are detected, the watcher emits a workspace-changed event to the frontend. The frontend listens for this event in the useWorkspace composable and triggers a workspace reload to synchronize with external changes.
Sources:
Command Lifecycle
Every command follows a consistent lifecycle pattern that ensures data consistency and error handling.
Standard Command Pattern
Command Parameter Patterns
Commands follow consistent parameter patterns based on their scope:
Workspace-scoped commands:
- Take
root_path: Stringto identify the workspace root (path to aTODO/directory) - Example:
load_workspace(root_path: String)
Board-scoped commands:
- Take
root_path: Stringandboard_path: String - Example:
save_board_file(root_path: String, board_path: String, markdown: String)
Card-scoped commands:
- Take
root_path: Stringandcard_path: String - Example:
save_card_file(root_path: String, card_path: String, markdown: String)
Return Value Convention
All commands that modify workspace state return a fresh WorkspaceSnapshot. This ensures the frontend always has a consistent view of the file system after operations complete. Commands that only read state (like load_app_config) return their specific data types.
Sources:
Shared Command Support
The commands/support.rs module provides shared helpers used across all command categories to avoid code duplication and ensure consistent behavior.
Support Module Responsibilities
The support module handles:
- Path Resolution: Converting relative board/card paths to absolute file system paths
- Board Path Validation: Ensuring board paths resolve to
TODO/todo.mdfiles - Card Path Validation: Ensuring card paths resolve to
cards/*.mdfiles - Slug Extraction: Parsing card slugs from file paths
- Write Building: Creating
FileWritestructures for common operations
Typical Command Support Flow
By centralizing path resolution and validation in the support module, individual command handlers remain focused on their specific operations while maintaining consistent path handling across the entire command layer.
Sources:
Error Handling
Command handlers use Rust's Result<T, String> type for error handling, with string error messages propagated to the frontend.
Error Propagation Pattern
Commands that modify state typically return Result<WorkspaceSnapshot, String>:
// Conceptual example (not actual code)
#[tauri::command]
fn save_card_file(
root_path: String,
card_path: String,
markdown: String
) -> Result<WorkspaceSnapshot, String> {
// Validation can fail
let resolved_path = resolve_card_path(&root_path, &card_path)?;
// Write can fail
apply_workspace_writes(root_path, vec![write])?;
// Reload can fail
let snapshot = load_workspace_snapshot(root_path)?;
Ok(snapshot)
}Frontend Error Handling
When commands fail, the frontend receives a rejected promise with the error message:
// Conceptual example (not actual code)
try {
const snapshot = await invoke('save_card_file', {
rootPath,
cardPath,
markdown
});
// Apply snapshot to state
} catch (error) {
// Display error message to user
console.error('Failed to save card:', error);
}This pattern keeps error handling simple while providing enough context for debugging. The backend ensures atomicity by rolling back partial writes when errors occur during multi-file operations.
Sources:
Command Integration Points
Commands integrate with several other backend systems to provide complete functionality.
Integration Architecture
Commands serve as orchestration points that:
- Validate and resolve parameters
- Delegate to workspace modules for actual work
- Manage Tauri-specific concerns (state, events)
- Return consistent snapshot results
- Handle error propagation
This separation allows workspace modules to remain pure Rust functions with no Tauri dependencies, making them testable and reusable.
Sources:
