Agent skill

Refactor

by atilladeniz in atilladeniz/Kubeli

Refactors code following Ousterhout's design principles. An agent skill from atilladeniz/Kubeli.

MITAuto-check: warningsDevelopment

Install Refactor

The automated check flagged lines worth reading first. See the safety section below.

skills CLI
$ npx skills add atilladeniz/Kubeli --skill refactor -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install atilladeniz/Kubeli refactor --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ 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-src

Use ~/.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/

Facts

Skill name
refactor
GitHub stars
387
Token cost
~7.7k tokens
SKILL.md length
1,165 words
Files
1
Skills in repo
3
Repo updated
First seen
Licence
MIT

At a glance

Refactors code following Ousterhout's design principles. An agent skill from atilladeniz/Kubeli.

  • Works in 6 steps: Analysis (Use /software-design-review… → Safety Checklist → Clean Code Smells Checklist (Robert… → …
  • Tasks that involve Refactoring
  • SKILL.md covers Kubeli Tech Stack, Phase 1: Analysis (Use…, Phase 2: Safety Checklist and Phase 3: Clean Code Smells…, plus 5 more sections
  • Calls git, cargo and npm

What it does

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.

When your agent uses it

  • Tasks that involve Refactoring
  • Tasks that involve Container orchestration
  • Tasks that involve State management

Example prompts

  • “Use the refactor skill to refactor code following Ousterhout's design principles. An agent skill from atilladeniz/Kubeli”
  • “/refactor”

Workflow steps

6 steps, taken from the step headings in SKILL.md.

  1. Analysis (Use /software-design-review principles)
  2. Safety Checklist
  3. Clean Code Smells Checklist (Robert Martin)
  4. Stack-Specific Refactoring Patterns
  5. Refactoring Workflow
  6. Prioritization Matrix

What it can do on your machine

Read from SKILL.md and the folder at commit 444659b. It shows what the files ask for, not the result of running them.

  • Tool permissions

    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.

  • Runs code

    Shell commands in SKILL.md call:

    • git
    • cargo
    • npm

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    Links to these hosts (documentation or services it may open):

    • github.com
    • vite.dev
    • rust-unofficial.github.io
    • v2.tauri.app
    • developerway.com
    • alexkondov.com
    • corrode.dev
    • blog.logrocket.com

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

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.

Always · name and description, kept in context so the agent knows when to use it
~55
When it runs · the whole SKILL.md, loaded when a task matches
~7.7k

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.

Safety

Auto-check: warnings

The automated check found patterns that need a careful read before installing.

  • WarningMentions a credentials file (SSH keys, cloud or package-manager tokens)SKILL.md:720
    "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.

SKILL.md

The full file from atilladeniz/Kubeli at commit 444659b, republished under its MIT licence (© atilladeniz). 1,165 words, ~7,678 tokens.

Download SKILL.mdSave it as .claude/skills/refactor/SKILL.md (or your agent's skills folder).
name
refactor
description
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.
argument-hint
file_or_directory_path

Strategic Refactoring Skill

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.

Kubeli Tech Stack

  • Frontend: Vite 7+, React 19, TypeScript
  • Desktop: Tauri 2.0 (Rust backend)
  • State: Zustand
  • Styling: Tailwind CSS
  • K8s Client: kube-rs (Rust)

Phase 1: Analysis (Use /software-design-review principles)

Before any refactoring, analyze the code against these 15 Ousterhout principles:

  1. Strategic vs. Tactical Programming
  2. Module Depth (Deep vs. Shallow)
  3. Somewhat General-Purpose (Generalization)
  4. Different Layers, Different Abstractions
  5. Information Hiding & Leaks
  6. Pull Complexity Downward
  7. Together or Separate?
  8. Define Errors Out of Existence
  9. Design Twice
  10. Consistency
  11. Code Should Be Obvious
  12. Comments & Documentation
  13. Names
  14. Write Comments First
  15. Modifying Existing Code

Phase 2: Safety Checklist

Before ANY refactoring:

  • Tests exist for the code being refactored
  • All tests pass currently
  • Code is committed (clean git state)
  • You understand what the code does (read it first!)

If tests don't exist:

  1. Write characterization tests first
  2. Test the component as a black box
  3. Validate end results, not implementation details

Phase 3: Clean Code Smells Checklist (Robert Martin)

In addition to Ousterhout's principles, check for these code smells:

Comments (C1-C5)
CodeSmellFix
C1Ungeeignete Informationen (Change history, author info)Remove, use git
C2Überholte KommentareUpdate or delete
C3Redundante KommentareDelete if code is self-explanatory
C4Schlecht geschriebene KommentareRewrite clearly
C5Auskommentierter CodeDelete (git has history)
Functions (F1-F4)
CodeSmellFix
F1Zu viele Argumente (>3)Use object parameter
F2Output-ArgumenteReturn value instead
F3Flag-Argumente (boolean params)Split into two functions
F4Tote Funktionen (never called)Delete
General (G1-G36) - Most Important
CodeSmellFix
G2Offensichtliches Verhalten fehltImplement expected behavior
G3Falsches Verhalten an GrenzenAdd boundary tests
G5Duplizierung (DRY)Extract common code
G6Falsche AbstraktionsebeneMove to correct layer
G8Zu viele Informationen (large interface)Hide details, minimize API
G9Toter CodeDelete
G10Vertikale Trennung (related code far apart)Move together
G11InkonsistenzFollow established patterns
G13Künstliche KopplungDecouple unrelated code
G14Funktionsneid (Feature Envy)Move method to correct class
G16Verdeckte Absicht (obscure code)Make obvious
G17Falsche ZuständigkeitMove to responsible module
G23If/Else statt PolymorphismusUse polymorphism
G25Magische ZahlenNamed constants
G28Bedingungen nicht eingekapseltExtract to named function
G29Negative BedingungenUse positive conditions
G30Mehr als eine AufgabeSplit function
G31Verborgene zeitliche KopplungenMake dependencies explicit
G33Grenzbedingungen nicht eingekapseltEncapsulate bounds
G34Mehrere Abstraktionsebenen gemischtOne level per function
G36Transitive Navigation (Law of Demeter)Don't talk to strangers
Names (N1-N7)
CodeSmellFix
N1Nicht deskriptivRename to describe purpose
N2Falsche AbstraktionsebeneMatch name to abstraction level
N4Nicht eindeutigMake unambiguous
N5Zu kurz für großen ScopeLonger names for wider scope
N7Nebeneffekte nicht im NamenInclude side effects in name
Tests (T1-T9)
CodeSmellFix
T1Unzureichende TestsAdd more tests
T3Triviale Tests übersprungenTest everything
T5Grenzbedingungen nicht getestetAdd boundary tests
T6Bug-Nachbarschaft nicht getestetTest around bugs
T9Langsame TestsOptimize test speed
F.I.R.S.T. Test Principles
  • Fast: Tests should run quickly
  • Independent: Tests shouldn't depend on each other
  • Repeatable: Same result every time
  • Self-Validating: Boolean output (pass/fail)
  • Timely: Written before/with production code
Clean Code Function Rules
  1. Klein! Functions should be small (ideally < 20 lines)
  2. Eine Aufgabe - Do ONE thing and do it well
  3. Eine Abstraktionsebene - Don't mix abstraction levels
  4. Stepdown Rule - Read code top-down like a story
  5. Max 3 Arguments - Prefer 0-2, use object for more
typescript
// 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);
}
Law of Demeter (G36: Transitive Navigation)

Principle: A method should only call methods on:

  • Its own object (this)
  • Objects passed as parameters
  • Objects it creates
  • Its direct component objects
typescript
// 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();
Pfadfinder-Regel (Boy Scout Rule)

"Leave the code cleaner than you found it."

Every time you touch code:

  • Fix one small thing
  • Improve one name
  • Extract one function
  • Add one missing test

Phase 4: Stack-Specific Refactoring Patterns

Show full SKILL.md (483 more words)Show less
Vite/React (Frontend)

Component Organization:

typescript
// 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:

SmellRefactoring
Props drilling through 3+ levelsUse Zustand store or Context
Giant utils.ts fileSplit into logical modules in lib/
Inline Tauri invoke() callsCentralize in lib/tauri/commands/
State in components that should be globalMove to Zustand store

Zustand (State Management)

Selective State Access:

typescript
// 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:

typescript
// 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:

typescript
// 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);
  // ...
}

Tauri 2.0 / Rust (Backend)

Command Organization:

rust
// 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:

rust
// 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:

rust
// 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);
rust
// 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 => { ... }
}
rust
// 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:

rust
// 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
}

Tauri 2.0 Enterprise Patterns

Command Layer Pattern (Thin Handlers → Service Layer):

rust
// 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):

rust
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):

rust
// 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:

rust
#[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):

rust
// 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:

rust
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):

rust
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(())
}
typescript
// 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:

json
// 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:

toml
# 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 symbols

Channels for High-Throughput Streaming (Alternative to Events):

rust
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();
}
typescript
// 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:

json
// 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):

json
// 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:

  • Enable strict CSP with default-src 'self'
  • Configure per-window capabilities with minimum permissions
  • Define scopes to restrict file system access
  • Validate ALL command inputs in Rust (frontend is untrusted!)
  • Run cargo audit and npm audit regularly
  • Never load remote/untrusted content
  • Sign all release binaries
  • Use tokio::sync::Mutex for async commands (not std::sync)

Splashscreen Startup Optimization:

rust
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):

rust
// 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:

rust
#[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!");
    }
}
toml
# Enable test feature in Cargo.toml
[dependencies]
tauri = { version = "2.0", features = ["test"] }

Testing: Frontend IPC Mocking (Vitest):

typescript
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:

toml
# 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:

toml
edition = "2021"
max_width = 100
imports_granularity = "Module"
group_imports = "StdExternalCrate"
wrap_comments = true

Workspace Dependency Management:

toml
# 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 = true

React / TypeScript Patterns

Component Cohesion (Single Responsibility):

typescript
// 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 store

Props Interface Simplification:

typescript
// 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:

typescript
// 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 });
  // ...
}

Phase 5: Refactoring Workflow

Step-by-Step Process
  1. Analyze (5-10 min)

    • Run /software-design-review on target code
    • Identify top 3 complexity issues
    • Choose ONE to fix first
  2. Design (5 min)

    • Consider 2-3 alternative approaches
    • Pick the one with simplest interface
    • Write the interface comment FIRST
  3. Test (before coding)

    • Ensure tests exist
    • If not, write characterization tests
    • Run tests to confirm green
  4. Refactor (small steps)

    • Make ONE change at a time
    • Run tests after each change
    • Commit after each working step
  5. Review (after)

    • Does the code look like it was designed this way?
    • Is the interface simpler?
    • Did we improve or just move complexity?
Commit Strategy
bash
# 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 vague

Phase 6: Prioritization Matrix

Rate each issue and fix highest impact first:

IssueComplexity ReductionEffortRiskPriority
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

Your Output Format

1. Analysis Summary
text
Target: [file/directory]
Current Complexity: [Low/Medium/High]
Top Issues:
1. [Issue + Principle violated]
2. [Issue + Principle violated]
3. [Issue + Principle violated]
2. Refactoring Plan
text
Priority | Issue | Refactoring | Estimated Changes
---------|-------|-------------|------------------
P0       | ...   | ...         | ~X files, ~Y lines
P1       | ...   | ...         | ...
3. Step-by-Step Execution

For each P0/P1 item:

  1. What to change
  2. Expected interface (comment first)
  3. Test requirements
  4. Implementation steps
4. Safety Notes
  • Tests to add/verify
  • Potential breaking changes
  • Rollback plan if needed

Sources & References

Books
  • John Ousterhout: "A Philosophy of Software Design" (15 Principles)
  • Robert C. Martin: "Clean Code" (Smells & Heuristics)
  • Martin Fowler: "Refactoring" (Refactoring Catalog)
Web Resources

© atilladeniz, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

Just SKILL.md in .claude/skills/refactor of atilladeniz/Kubeli.

Open the folder on GitHubat commit 444659b

Compare with similar skills

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.

Refactor compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Refactor this skillatilladeniz/Kubeli387—~7.7kAutomated safety check: WarnMIT
Store Managementbkywksj/knowledge-base330—~1.2kAutomated safety check: PassCustom licence
Cdphuoshen80/ReinaManager693—~178Automated safety check: PassAGPL-3.0
React Generate Skilljiushiwon/wg-skills112—~2.8kAutomated safety check: PassApache-2.0
Nuqstrycompai/crm11k1 repos~1.7kAutomated safety check: PassMIT
Cut Releasedelexw/claude-code-trace3771 repos~1.4kAutomated safety check: PassMIT

Similar skills

  • Store Management

    bkywksj/knowledge-base

    Tauri 状态管理技能,覆盖 React 前端状态和 Rust 后端状态管理. An agent skill from bkywksj/knowledge-base.

    330 GitHub stars~1.2k tokensUpdated 6 days ago
    Frontend & DesignAuto-check passed
  • Cdp

    huoshen80/ReinaManager

    通过 CDP 连接 ReinaManager WebView2,复现、诊断并验证真实应用的前端问题。仅在用户显式调用 /cdp 或 $cdp 进行前端调试时使用。

    693 GitHub stars~178 tokensUpdated 5 days ago
    DatabasesAuto-check passed
  • React Generate Skill

    jiushiwon/wg-skills

    This skill should be used when the user wants to create a standardized React 18 + TypeScript + Vite + Zustand project from scratch.

    112 GitHub stars~2.8k tokensUpdated yesterday
    Frontend & DesignAuto-check passed
  • Nuqs

    trycompai/crm

    nuqs (type-safe URL query state) best practices for Next.js and other React frameworks.

    11k GitHub starsUsed in 1 repo~1.7k tokens
    DevelopmentAuto-check passed
  • Cut Release

    delexw/claude-code-trace

    Cuts a new versioned release of claude-code-trace end-to-end without asking any questions.

    377 GitHub starsUsed in 1 repo~1.4k tokens
    DevelopmentAuto-check passed
  • Cursor BYOK Frontend Guide

    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.

    3.2k GitHub stars~1.9k tokensUpdated yesterday
    Frontend & DesignAuto-check passed

More from atilladeniz/Kubeli

  • Vet

    atilladeniz/Kubeli

    Run vet immediately after ANY logical unit of code changes. An agent skill from atilladeniz/Kubeli.

    387 GitHub starsUsed in 3 repos~1.6k tokens
    Auto-check passed
  • Software Design Review

    atilladeniz/Kubeli

    Analyzes code based on John Ousterhout's "A Philosophy of Software Design".

    387 GitHub stars~5.3k tokensUpdated 3 days ago
    Auto-check passed

Categories

Questions about Refactor

What does Refactor do?

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.

When should I use Refactor?

Refactor fits situations like: tasks that involve Refactoring; tasks that involve Container orchestration; tasks that involve State management.

How do I install Refactor in Claude Code?

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.

How do I install Refactor in Codex?

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.

Can I use Refactor in Cursor, Gemini CLI or GitHub Copilot?

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.

What does Refactor need to run?

Going by SKILL.md and its folder, Refactor needs the command-line tools its instructions call (git, cargo and npm).

Does Refactor access the network?

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.

Is Refactor safe to install?

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.

What licence does Refactor use?

Refactor is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Refactor use?

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.

What are the alternatives to Refactor?

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.

Who maintains Refactor?

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.