Store Management
bkywksj/knowledge-base
Tauri 状态管理技能,覆盖 React 前端状态和 Rust 后端状态管理. An agent skill from bkywksj/knowledge-base.
Refactors code following Ousterhout's design principles. An agent skill from atilladeniz/Kubeli.
The automated check flagged lines worth reading first. See the safety section below.
$ npx skills add atilladeniz/Kubeli --skill refactor -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install atilladeniz/Kubeli refactor --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/atilladeniz/Kubeli.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.claude/skills/refactor .claude/skills/refactor && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "refactor" agent skill from https://github.com/atilladeniz/Kubeli/tree/main/.claude/skills/refactor into .claude/skills/refactor/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "refactor", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/atilladeniz/Kubeli/tree/main/.claude/skills/refactorType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add atilladeniz/Kubeli --skill refactor -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install atilladeniz/Kubeli refactor --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/atilladeniz/Kubeli.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.claude/skills/refactor .agents/skills/refactor && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "refactor" agent skill from https://github.com/atilladeniz/Kubeli/tree/main/.claude/skills/refactor into .agents/skills/refactor/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "refactor", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add atilladeniz/Kubeli --skill refactor -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install atilladeniz/Kubeli refactor --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/atilladeniz/Kubeli.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.claude/skills/refactor .cursor/skills/refactor && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "refactor" agent skill from https://github.com/atilladeniz/Kubeli/tree/main/.claude/skills/refactor into .cursor/skills/refactor/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "refactor", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/atilladeniz/Kubeli.git --path .claude/skills/refactor--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add atilladeniz/Kubeli --skill refactor -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install atilladeniz/Kubeli refactor --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/atilladeniz/Kubeli.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.claude/skills/refactor .gemini/skills/refactor && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "refactor" agent skill from https://github.com/atilladeniz/Kubeli/tree/main/.claude/skills/refactor into .gemini/skills/refactor/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "refactor", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install atilladeniz/Kubeli refactorInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add atilladeniz/Kubeli --skill refactor -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/atilladeniz/Kubeli.git skills-src && mkdir -p .github/skills && cp -r skills-src/.claude/skills/refactor .github/skills/refactor && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "refactor" agent skill from https://github.com/atilladeniz/Kubeli/tree/main/.claude/skills/refactor into .github/skills/refactor/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "refactor", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add atilladeniz/Kubeli --skill refactor -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install atilladeniz/Kubeli refactor --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/atilladeniz/Kubeli.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.claude/skills/refactor .opencode/skills/refactor && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "refactor" agent skill from https://github.com/atilladeniz/Kubeli/tree/main/.claude/skills/refactor into .opencode/skills/refactor/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "refactor", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
refactorRefactors code following Ousterhout's design principles. An agent skill from atilladeniz/Kubeli.
Refactor is an agent skill from atilladeniz/Kubeli. Refactors code following Ousterhout's design principles. Analyzes complexity, creates prioritized refactoring plan, and executes with safety-first approach. Optimized for Vite/React, Tauri/Rust, Zustand stack.
Its SKILL.md is about 7.7k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.
It sits in Development, covering Refactoring, Container orchestration and State management. It works with Kubernetes, React, Rust and Tauri. The repository describes itself as: A modern Kubernetes GUI management desktop app for macOS & Windows. Multi-cluster support, real-time monitoring, AI assistant, terminal access, and more. The licence is MIT.
6 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit 444659b. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
gitcargonpmFrom the folder's file list and the shell code blocks in SKILL.md.
Links to these hosts (documentation or services it may open):
github.comvite.devrust-unofficial.github.iov2.tauri.appdeveloperway.comalexkondov.comcorrode.devblog.logrocket.comFrom URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Refactor loads about 7.7k tokens when it runs. Until then it costs about 55 tokens; SKILL.md has 1,165 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found patterns that need a careful read before installing.
"deny": [{ "path": "$HOME/.ssh/*" }]Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from atilladeniz/Kubeli at commit 444659b, republished under its MIT licence (© atilladeniz). 1,165 words, ~7,678 tokens.
.claude/skills/refactor/SKILL.md (or your agent's skills folder).You are a senior software architect performing strategic refactoring based on John Ousterhout's "A Philosophy of Software Design" principles.
Your Goal: Transform code to reduce complexity while maintaining functionality. Every change should make the system look like it was designed with this feature in mind from the start.
Before any refactoring, analyze the code against these 15 Ousterhout principles:
Before ANY refactoring:
If tests don't exist:
In addition to Ousterhout's principles, check for these code smells:
| Code | Smell | Fix |
|---|---|---|
| C1 | Ungeeignete Informationen (Change history, author info) | Remove, use git |
| C2 | Überholte Kommentare | Update or delete |
| C3 | Redundante Kommentare | Delete if code is self-explanatory |
| C4 | Schlecht geschriebene Kommentare | Rewrite clearly |
| C5 | Auskommentierter Code | Delete (git has history) |
| Code | Smell | Fix |
|---|---|---|
| F1 | Zu viele Argumente (>3) | Use object parameter |
| F2 | Output-Argumente | Return value instead |
| F3 | Flag-Argumente (boolean params) | Split into two functions |
| F4 | Tote Funktionen (never called) | Delete |
| Code | Smell | Fix |
|---|---|---|
| G2 | Offensichtliches Verhalten fehlt | Implement expected behavior |
| G3 | Falsches Verhalten an Grenzen | Add boundary tests |
| G5 | Duplizierung (DRY) | Extract common code |
| G6 | Falsche Abstraktionsebene | Move to correct layer |
| G8 | Zu viele Informationen (large interface) | Hide details, minimize API |
| G9 | Toter Code | Delete |
| G10 | Vertikale Trennung (related code far apart) | Move together |
| G11 | Inkonsistenz | Follow established patterns |
| G13 | Künstliche Kopplung | Decouple unrelated code |
| G14 | Funktionsneid (Feature Envy) | Move method to correct class |
| G16 | Verdeckte Absicht (obscure code) | Make obvious |
| G17 | Falsche Zuständigkeit | Move to responsible module |
| G23 | If/Else statt Polymorphismus | Use polymorphism |
| G25 | Magische Zahlen | Named constants |
| G28 | Bedingungen nicht eingekapselt | Extract to named function |
| G29 | Negative Bedingungen | Use positive conditions |
| G30 | Mehr als eine Aufgabe | Split function |
| G31 | Verborgene zeitliche Kopplungen | Make dependencies explicit |
| G33 | Grenzbedingungen nicht eingekapselt | Encapsulate bounds |
| G34 | Mehrere Abstraktionsebenen gemischt | One level per function |
| G36 | Transitive Navigation (Law of Demeter) | Don't talk to strangers |
| Code | Smell | Fix |
|---|---|---|
| N1 | Nicht deskriptiv | Rename to describe purpose |
| N2 | Falsche Abstraktionsebene | Match name to abstraction level |
| N4 | Nicht eindeutig | Make unambiguous |
| N5 | Zu kurz für großen Scope | Longer names for wider scope |
| N7 | Nebeneffekte nicht im Namen | Include side effects in name |
| Code | Smell | Fix |
|---|---|---|
| T1 | Unzureichende Tests | Add more tests |
| T3 | Triviale Tests übersprungen | Test everything |
| T5 | Grenzbedingungen nicht getestet | Add boundary tests |
| T6 | Bug-Nachbarschaft nicht getestet | Test around bugs |
| T9 | Langsame Tests | Optimize test speed |
// BEFORE: Too many args, mixed abstraction levels
async function processPod(
namespace: string,
name: string,
action: string,
force: boolean,
gracePeriod: number,
callback: () => void
) {
const pod = await invoke('get_pod', { namespace, name });
if (action === 'delete') {
if (force) {
await invoke('force_delete', { namespace, name });
} else {
await invoke('delete', { namespace, name, gracePeriod });
}
}
callback();
}
// AFTER: Single purpose, one abstraction level
interface PodActionRequest {
pod: PodRef;
action: PodAction;
}
async function executePodAction({ pod, action }: PodActionRequest): Promise<void> {
const handler = getPodActionHandler(action);
await handler.execute(pod);
}Principle: A method should only call methods on:
this)// VIOLATES Law of Demeter: "Train wreck"
const street = user.getAddress().getCity().getStreet();
// BETTER: Tell, don't ask
const street = user.getStreetAddress();
// Kubeli Example:
// BAD: Navigating through objects
const podName = store.getState().cluster.selectedPod.metadata.name;
// GOOD: Direct access with selector
const podName = useSelectedPodName();"Leave the code cleaner than you found it."
Every time you touch code:
Component Organization:
// BEFORE: Monolithic component with mixed concerns
export function PodList({ namespace }: Props) {
const [pods, setPods] = useState([]);
const [filter, setFilter] = useState('');
useEffect(() => { fetchPods().then(setPods); }, []);
return (
<div>
<input value={filter} onChange={e => setFilter(e.target.value)} />
<ul>{pods.filter(p => p.name.includes(filter)).map(p => <PodItem pod={p} />)}</ul>
</div>
);
}
// AFTER: Separate data from presentation, use Zustand
// stores/resource-store.ts
export const useResourceStore = create((set) => ({
pods: [],
fetchPods: async (ns) => { /* ... */ },
}));
// components/PodList.tsx
export function PodList() {
const pods = useResourceStore(s => s.pods);
const [filter, setFilter] = useState('');
return <ul>{pods.filter(p => p.name.includes(filter)).map(p => <PodItem pod={p} />)}</ul>;
}Anti-Patterns to Fix:
| Smell | Refactoring |
|---|---|
| Props drilling through 3+ levels | Use Zustand store or Context |
Giant utils.ts file | Split into logical modules in lib/ |
Inline Tauri invoke() calls | Centralize in lib/tauri/commands/ |
| State in components that should be global | Move to Zustand store |
Selective State Access:
// BEFORE: Re-renders on ANY state change
function PodCount() {
const store = useClusterStore(); // BAD: subscribes to everything
return <span>{store.pods.length}</span>;
}
// AFTER: Only re-renders when pods change
function PodCount() {
const podCount = useClusterStore((s) => s.pods.length); // GOOD: selective
return <span>{podCount}</span>;
}Modular Stores with Slices:
// BEFORE: Monolithic store
const useStore = create((set) => ({
pods: [],
deployments: [],
services: [],
selectedPod: null,
selectedDeployment: null,
// ... 50 more properties
}));
// AFTER: Composable slices
// stores/pods-slice.ts
export const createPodsSlice = (set, get) => ({
pods: [],
selectedPod: null,
fetchPods: async (ns) => { ... },
selectPod: (id) => set({ selectedPod: id }),
});
// stores/deployments-slice.ts
export const createDeploymentsSlice = (set, get) => ({
deployments: [],
fetchDeployments: async (ns) => { ... },
});
// stores/index.ts
export const useStore = create((...a) => ({
...createPodsSlice(...a),
...createDeploymentsSlice(...a),
}));Custom Hook Abstraction:
// BEFORE: Direct store access everywhere
function PodDetails({ id }: Props) {
const pods = useClusterStore((s) => s.pods);
const pod = pods.find(p => p.id === id);
// ...
}
// AFTER: Domain-specific hooks
// hooks/usePod.ts
export function usePod(id: string) {
return useClusterStore((s) => s.pods.find(p => p.id === id));
}
// components/PodDetails.tsx
function PodDetails({ id }: Props) {
const pod = usePod(id);
// ...
}Command Organization:
// BEFORE: All commands in one file
// src-tauri/src/main.rs
#[tauri::command]
fn get_pods() { ... }
#[tauri::command]
fn get_deployments() { ... }
#[tauri::command]
fn get_services() { ... }
// ... 50 more commands
// AFTER: Modular command structure
// src-tauri/src/commands/mod.rs
pub mod pods;
pub mod deployments;
pub mod services;
// src-tauri/src/commands/pods.rs
#[tauri::command]
pub async fn get_pods(state: State<'_, AppState>, namespace: &str) -> Result<Vec<Pod>, Error> {
let client = state.client_manager.get_client()?;
client.list_pods(namespace).await
}
// src-tauri/src/main.rs
fn main() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![
commands::pods::get_pods,
commands::pods::delete_pod,
commands::deployments::get_deployments,
])
.run(tauri::generate_context!())
.expect("error running app");
}Separation: main.rs vs lib.rs:
// BEFORE: Logic in main.rs
// src-tauri/src/main.rs
fn main() {
// 500 lines of logic...
}
// AFTER: main.rs only handles startup, lib.rs has logic
// src-tauri/src/main.rs
fn main() {
kubeli_lib::run();
}
// src-tauri/src/lib.rs
pub mod commands;
pub mod k8s;
pub mod state;
pub fn run() {
tauri::Builder::default()
.manage(state::AppState::new())
.invoke_handler(tauri::generate_handler![...])
.run(tauri::generate_context!())
.expect("error running app");
}Rust Refactoring Patterns:
// BEFORE: Tuple returns (hard to understand)
fn get_cluster_info() -> (String, bool, u32) {
(context_name, is_connected, node_count)
}
let (a, b, c) = get_cluster_info(); // What is a, b, c?
// AFTER: Struct with meaningful names
struct ClusterInfo {
context_name: String,
is_connected: bool,
node_count: u32,
}
fn get_cluster_info() -> ClusterInfo { ... }
let info = get_cluster_info();
println!("Connected: {}", info.is_connected);// BEFORE: if-else chains
if status == "Running" { ... }
else if status == "Pending" { ... }
else if status == "Failed" { ... }
// AFTER: Pattern matching with enum
enum PodStatus { Running, Pending, Failed, Unknown }
match pod.status {
PodStatus::Running => { ... }
PodStatus::Pending => { ... }
PodStatus::Failed => { ... }
PodStatus::Unknown => { ... }
}// BEFORE: Manual error handling everywhere
fn get_pod(name: &str) -> Result<Pod, Error> {
let pods = self.list_pods()?;
for pod in pods {
if pod.name == name {
return Ok(pod);
}
}
Err(Error::NotFound)
}
// AFTER: Iterator methods with Option/Result
fn get_pod(&self, name: &str) -> Option<&Pod> {
self.pods.iter().find(|p| p.name == name)
}
// Or with Result if error info needed:
fn get_pod(&self, name: &str) -> Result<&Pod, Error> {
self.pods.iter()
.find(|p| p.name == name)
.ok_or_else(|| Error::PodNotFound(name.to_string()))
}Minimize Public API Surface:
// BEFORE: Everything public
pub struct KubeClientManager {
pub clients: HashMap<String, Client>,
pub current_context: String,
pub config: KubeConfig,
}
// AFTER: Minimal public API, private internals
pub struct KubeClientManager {
clients: HashMap<String, Client>, // private
current_context: String, // private
config: KubeConfig, // private
}
impl KubeClientManager {
pub fn new() -> Result<Self, Error> { ... }
pub fn get_client(&self) -> Result<&Client, Error> { ... }
pub fn switch_context(&mut self, name: &str) -> Result<(), Error> { ... }
// Internal methods stay private
}Command Layer Pattern (Thin Handlers → Service Layer):
// BEFORE: Fat command with business logic
#[tauri::command]
pub async fn create_user(name: String, email: String) -> Result<User, String> {
// Validation here...
// Database access here...
// Business logic here...
// 100+ lines of mixed concerns
}
// AFTER: Thin handler → Service layer
// src/commands/user_commands.rs
#[tauri::command]
pub async fn create_user(name: String, email: String) -> Result<User, AppError> {
user_service::create_user(&name, &email).await
}
// src/services/user_service.rs
pub async fn create_user(name: &str, email: &str) -> Result<User, AppError> {
validate_email(email)?;
let user = User::new(name, email);
repository::save_user(&user).await?;
Ok(user)
}Error Handling (thiserror + Serialize for IPC):
use thiserror::Error;
use serde::Serialize;
#[derive(Error, Debug)]
pub enum AppError {
#[error("Database error: {0}")]
Database(#[from] sqlx::Error),
#[error("File not found: {path}")]
FileNotFound { path: String },
#[error("Kubernetes error: {0}")]
Kube(#[from] kube::Error),
#[error(transparent)]
Other(#[from] anyhow::Error),
}
// CRITICAL: Implement Serialize for Tauri IPC
impl Serialize for AppError {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: serde::Serializer {
serializer.serialize_str(&self.to_string())
}
}
// For typed frontend errors, use tagged serialization:
#[derive(Serialize)]
#[serde(tag = "kind", content = "message")]
#[serde(rename_all = "camelCase")]
pub enum TypedError {
Io(String),
Validation(String),
NotFound(String),
}
// Produces: { kind: 'io' | 'validation' | 'notFound', message: string }State Management (std::Mutex vs tokio::Mutex):
// SYNC commands: Use std::sync::Mutex
use std::sync::Mutex;
#[tauri::command]
fn increment(state: State<'_, Mutex<AppState>>) -> u32 {
let mut state = state.lock().unwrap();
state.counter += 1;
state.counter
}
// ASYNC commands: Use tokio::sync::Mutex (avoids blocking!)
use tokio::sync::Mutex;
#[tauri::command]
async fn async_increment(state: State<'_, Mutex<AppState>>) -> Result<u32, ()> {
let mut state = state.lock().await; // .await not .unwrap()!
state.counter += 1;
Ok(state.counter)
}
// CRITICAL: Async commands with borrowed args need Result return type
// ❌ Won't compile
async fn cmd(state: State<'_, AppState>) { }
// ✅ Correct pattern
async fn cmd(state: State<'_, AppState>) -> Result<(), ()> { Ok(()) }Security: Path Traversal Prevention:
#[tauri::command]
async fn read_file(path: String, app: AppHandle) -> Result<String, String> {
let path = std::path::Path::new(&path);
// Prevent path traversal attacks
if path.components().any(|c| matches!(c, std::path::Component::ParentDir)) {
return Err("Invalid path: directory traversal not allowed".into());
}
// Validate against allowed base directory
let base = app.path().app_data_dir().unwrap();
let full_path = base.join(&path);
let canonical = full_path.canonicalize()
.map_err(|e| format!("Invalid path: {}", e))?;
if !canonical.starts_with(&base) {
return Err("Access denied: path outside allowed scope".into());
}
std::fs::read_to_string(canonical).map_err(|e| e.to_string())
}Async Performance (spawn_blocking for CPU-intensive):
// CPU-intensive work should use spawn_blocking
#[tauri::command]
async fn heavy_computation(data: Vec<u8>) -> Result<Vec<u8>, String> {
tokio::task::spawn_blocking(move || {
process_heavy_data(data) // Runs on blocking thread pool
}).await.map_err(|e| e.to_string())
}
// I/O work uses regular async
#[tauri::command]
async fn fetch_data(url: String) -> Result<Data, String> {
reqwest::get(&url).await
.map_err(|e| e.to_string())?
.json().await
.map_err(|e| e.to_string())
}Extension Traits for AppHandle:
pub trait AppHandleExt {
fn get_database(&self) -> Arc<Database>;
fn emit_global(&self, event: &str, payload: impl Serialize);
}
impl AppHandleExt for tauri::AppHandle {
fn get_database(&self) -> Arc<Database> {
self.state::<Arc<Database>>().inner().clone()
}
fn emit_global(&self, event: &str, payload: impl Serialize) {
self.emit(event, payload).unwrap();
}
}
// Usage in commands:
#[tauri::command]
async fn get_pods(app: AppHandle) -> Result<Vec<Pod>, AppError> {
let db = app.get_database();
db.query_pods().await
}Events for Real-time Updates (Backend → Frontend):
use tauri::{AppHandle, Emitter};
#[derive(Clone, Serialize)]
struct ProgressUpdate { percent: u32, status: String }
#[tauri::command]
async fn long_operation(app: AppHandle) -> Result<(), String> {
for i in 0..=100 {
app.emit("progress", ProgressUpdate {
percent: i,
status: format!("Processing {}%", i)
}).unwrap();
tokio::time::sleep(Duration::from_millis(50)).await;
}
Ok(())
}// Frontend: Always cleanup listeners!
import { listen } from '@tauri-apps/api/event';
const unlisten = await listen<ProgressUpdate>('progress', (event) => {
console.log(`Progress: ${event.payload.percent}%`);
});
// Cleanup on unmount
onCleanup(() => unlisten());Tauri 2.0 Capability-Based Security:
// src-tauri/capabilities/default.json
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "main-capability",
"windows": ["main"],
"permissions": [
"core:default",
"fs:default",
{
"identifier": "fs:allow-read",
"allow": [{ "path": "$APPDATA/*" }],
"deny": [{ "path": "$HOME/.ssh/*" }]
}
]
}Release Build Optimization:
# Cargo.toml
[profile.release]
lto = true # Link-time optimization
codegen-units = 1 # Better optimization
opt-level = "s" # Optimize for size
panic = "abort" # Smaller binary
strip = true # Remove debug symbolsChannels for High-Throughput Streaming (Alternative to Events):
use tauri::ipc::Channel;
#[derive(Clone, Serialize)]
#[serde(rename_all = "camelCase", tag = "event", content = "data")]
enum DownloadEvent<'a> {
Started { url: &'a str, size: u64 },
Progress { percent: u8, downloaded: u64 },
Finished,
}
#[tauri::command]
fn download(url: String, on_progress: Channel<DownloadEvent>) {
on_progress.send(DownloadEvent::Started { url: &url, size: 1024 }).unwrap();
// ... streaming data
for i in 0..=100 {
on_progress.send(DownloadEvent::Progress { percent: i, downloaded: i as u64 * 10 }).unwrap();
}
on_progress.send(DownloadEvent::Finished).unwrap();
}// Frontend: Channel usage
await invoke('download', {
url: 'https://example.com/file',
onProgress: new Channel<DownloadEvent>((event) => {
if (event.event === 'progress') {
console.log(`Downloaded: ${event.data.percent}%`);
}
})
});Multi-Window Security Isolation:
// capabilities/admin.json - More privileges
{
"identifier": "admin-capability",
"windows": ["admin-*"],
"permissions": ["fs:default", "fs:allow-write", "shell:allow-execute"]
}
// capabilities/viewer.json - Read-only
{
"identifier": "viewer-capability",
"windows": ["viewer-*"],
"permissions": ["fs:allow-read"]
}Content Security Policy (CSP):
// tauri.conf.json
{
"app": {
"security": {
"csp": {
"default-src": "'self' customprotocol: asset:",
"connect-src": "ipc: http://ipc.localhost",
"script-src": "'self'",
"style-src": "'unsafe-inline' 'self'"
}
}
}
}Security Hardening Checklist:
default-src 'self'cargo audit and npm audit regularlytokio::sync::Mutex for async commands (not std::sync)Splashscreen Startup Optimization:
tauri::Builder::default()
.setup(|app| {
let splashscreen = app.get_webview_window("splashscreen").unwrap();
let main_window = app.get_webview_window("main").unwrap();
tauri::async_runtime::spawn(async move {
// Heavy initialization here (doesn't block UI)
initialize_database().await;
load_config().await;
splashscreen.close().unwrap();
main_window.show().unwrap();
});
Ok(())
})Mobile Support (lib.rs Entry Point):
// src-tauri/src/lib.rs
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![...])
.run(tauri::generate_context!())
.expect("error running app");
}
// src-tauri/src/main.rs (minimal)
fn main() {
kubeli_lib::run();
}Testing: Rust Commands with Mock Runtime:
#[cfg(test)]
mod tests {
use tauri::test::{mock_builder, mock_context, noop_assets};
fn create_app() -> tauri::App<tauri::test::MockRuntime> {
mock_builder()
.invoke_handler(tauri::generate_handler![super::greet])
.build(mock_context(noop_assets()))
.expect("failed to build app")
}
#[test]
fn test_greet() {
let _app = create_app();
let result = super::greet("World");
assert_eq!(result, "Hello, World!");
}
}# Enable test feature in Cargo.toml
[dependencies]
tauri = { version = "2.0", features = ["test"] }Testing: Frontend IPC Mocking (Vitest):
import { mockIPC, clearMocks } from '@tauri-apps/api/mocks';
import { invoke } from '@tauri-apps/api/core';
afterEach(() => clearMocks());
test('invoke add command', async () => {
mockIPC((cmd, args) => {
if (cmd === 'add') return (args as { a: number; b: number }).a + args.b;
});
const result = await invoke('add', { a: 12, b: 15 });
expect(result).toBe(27);
});Code Quality: Clippy Configuration:
# Cargo.toml
[lints.clippy]
pedantic = { level = "warn", priority = -1 }
unwrap_used = "deny" # Force proper error handling
expect_used = "warn"
module_name_repetitions = "allow"Code Quality: rustfmt.toml:
edition = "2021"
max_width = 100
imports_granularity = "Module"
group_imports = "StdExternalCrate"
wrap_comments = trueWorkspace Dependency Management:
# Root Cargo.toml
[workspace.dependencies]
tauri = { version = "2.0", features = [] }
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1", features = ["full"] }
# Member Cargo.toml - inherit from workspace
[dependencies]
tauri.workspace = true
serde.workspace = trueComponent Cohesion (Single Responsibility):
// BEFORE: Component does too much
function PodManager() {
const [pods, setPods] = useState([]);
const [filter, setFilter] = useState('');
const [sortBy, setSortBy] = useState('name');
const [selectedPod, setSelectedPod] = useState(null);
const [isDeleting, setIsDeleting] = useState(false);
const [showLogs, setShowLogs] = useState(false);
// ... 200 lines of mixed concerns
return (
<div>
<FilterBar ... />
<PodList ... />
<PodDetails ... />
<DeleteConfirmation ... />
<LogViewer ... />
</div>
);
}
// AFTER: Separated concerns
function PodManager() {
return (
<PodFilterProvider>
<div>
<PodFilterBar />
<PodListWithSelection />
<PodDetailsPanel />
</div>
</PodFilterProvider>
);
}
// Each sub-component manages its own state or uses shared storeProps Interface Simplification:
// BEFORE: Too many props (shallow module)
interface PodCardProps {
name: string;
namespace: string;
status: string;
createdAt: Date;
labels: Record<string, string>;
onSelect: () => void;
onDelete: () => void;
onViewLogs: () => void;
onRestart: () => void;
isSelected: boolean;
showActions: boolean;
}
// AFTER: Deep module with simple interface
interface PodCardProps {
pod: Pod;
onAction?: (action: PodAction) => void;
}
type PodAction =
| { type: 'select' }
| { type: 'delete' }
| { type: 'viewLogs' }
| { type: 'restart' };Custom Hooks for Reusable Logic:
// BEFORE: Duplicated logic in components
function PodList() {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
useEffect(() => {
setLoading(true);
invoke('get_pods', { namespace })
.then(setData)
.catch(setError)
.finally(() => setLoading(false));
}, [namespace]);
// ...
}
// AFTER: Reusable hook
function useTauriQuery<T>(command: string, args: Record<string, unknown>) {
const [data, setData] = useState<T | null>(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<Error | null>(null);
useEffect(() => {
setLoading(true);
invoke<T>(command, args)
.then(setData)
.catch(setError)
.finally(() => setLoading(false));
}, [command, JSON.stringify(args)]);
return { data, loading, error };
}
// Usage
function PodList({ namespace }: Props) {
const { data: pods, loading, error } = useTauriQuery<Pod[]>('get_pods', { namespace });
// ...
}Analyze (5-10 min)
/software-design-review on target codeDesign (5 min)
Test (before coding)
Refactor (small steps)
Review (after)
# Small, atomic commits
git commit -m "refactor(pods): extract PodCard props into Pod type"
git commit -m "refactor(pods): create usePod hook for selective access"
git commit -m "refactor(pods): move pod filtering to dedicated hook"
# NOT one giant commit
git commit -m "refactor: improve pod management" # BAD: too vagueRate each issue and fix highest impact first:
| Issue | Complexity Reduction | Effort | Risk | Priority |
|---|---|---|---|---|
| High impact, Low effort, Low risk | ⬆️⬆️⬆️ | ⬇️ | ⬇️ | P0 - Do First |
| High impact, Medium effort | ⬆️⬆️⬆️ | ➡️ | ➡️ | P1 |
| Medium impact, Low effort | ⬆️⬆️ | ⬇️ | ⬇️ | P2 |
| Low impact OR High risk | ⬆️ | Any | ⬆️ | P3 - Later |
Target: [file/directory]
Current Complexity: [Low/Medium/High]
Top Issues:
1. [Issue + Principle violated]
2. [Issue + Principle violated]
3. [Issue + Principle violated]Priority | Issue | Refactoring | Estimated Changes
---------|-------|-------------|------------------
P0 | ... | ... | ~X files, ~Y lines
P1 | ... | ... | ...For each P0/P1 item:
© atilladeniz, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in .claude/skills/refactor of atilladeniz/Kubeli.
Open the folder on GitHubat commit 444659b
Refactor next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Refactor this skillatilladeniz/Kubeli | 387 | — | ~7.7k | Automated safety check: Warn | MIT | |
| Store Managementbkywksj/knowledge-base | 330 | — | ~1.2k | Automated safety check: Pass | Custom licence | |
| Cdphuoshen80/ReinaManager | 693 | — | ~178 | Automated safety check: Pass | AGPL-3.0 | |
| React Generate Skilljiushiwon/wg-skills | 112 | — | ~2.8k | Automated safety check: Pass | Apache-2.0 | |
| Nuqstrycompai/crm | 11k | 1 repos | ~1.7k | Automated safety check: Pass | MIT | |
| Cut Releasedelexw/claude-code-trace | 377 | 1 repos | ~1.4k | Automated safety check: Pass | MIT |
bkywksj/knowledge-base
Tauri 状态管理技能,覆盖 React 前端状态和 Rust 后端状态管理. An agent skill from bkywksj/knowledge-base.
huoshen80/ReinaManager
通过 CDP 连接 ReinaManager WebView2,复现、诊断并验证真实应用的前端问题。仅在用户显式调用 /cdp 或 $cdp 进行前端调试时使用。
jiushiwon/wg-skills
This skill should be used when the user wants to create a standardized React 18 + TypeScript + Vite + Zustand project from scratch.
trycompai/crm
nuqs (type-safe URL query state) best practices for Next.js and other React frameworks.
delexw/claude-code-trace
Cuts a new versioned release of claude-code-trace end-to-end without asking any questions.
leookun/cursor-byok
Sets the rules for building the Cursor BYOK desktop app's React and Tauri frontend, especially its HTTP boundary and component state architecture.
atilladeniz/Kubeli
Run vet immediately after ANY logical unit of code changes. An agent skill from atilladeniz/Kubeli.
atilladeniz/Kubeli
Analyzes code based on John Ousterhout's "A Philosophy of Software Design".
Categories
Refactors code following Ousterhout's design principles. An agent skill from atilladeniz/Kubeli. Refactor is an agent skill from atilladeniz/Kubeli. Refactors code following Ousterhout's design principles.
Refactor fits situations like: tasks that involve Refactoring; tasks that involve Container orchestration; tasks that involve State management.
Run `npx skills add atilladeniz/Kubeli --skill refactor -a claude-code`. Or copy the skill folder (.claude/skills/refactor in atilladeniz/Kubeli) into .claude/skills/refactor in your project. Claude Code loads it when a task matches its description.
Run `npx skills add atilladeniz/Kubeli --skill refactor -a codex`. Or copy the skill folder (.claude/skills/refactor in atilladeniz/Kubeli) into .agents/skills/refactor in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add atilladeniz/Kubeli --skill refactor -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/refactor, .gemini/skills/refactor, .github/skills/refactor and .opencode/skills/refactor in your project.
Going by SKILL.md and its folder, Refactor needs the command-line tools its instructions call (git, cargo and npm).
SKILL.md names 8 domains. As links in the text: github.com, vite.dev, rust-unofficial.github.io, v2.tauri.app, developerway.com, alexkondov.com, corrode.dev and blog.logrocket.com. This is read from the text; nothing was executed.
Our automated static check of SKILL.md flagged 1 warning(s): mentions a credentials file (ssh keys, cloud or package-manager tokens). Read the flagged lines before installing; the check is not a guarantee either way.
Refactor is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 7.7k tokens (SKILL.md is roughly 31k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Refactor: Store Management (bkywksj/knowledge-base, 330 stars), Cdp (huoshen80/ReinaManager, 693 stars), React Generate Skill (jiushiwon/wg-skills, 112 stars) and Nuqs (trycompai/crm, 11k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
atilladeniz (a GitHub user) maintains it in atilladeniz/Kubeli, which has 387 GitHub stars. The repository holds 3 skills in this directory. The repository was last updated on October 5, 2026.
Source: atilladeniz/Kubeli on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.