diff --git a/common/src/cmd.rs b/common/src/cmd.rs
index 614d86bb72..69398bf91f 100644
--- a/common/src/cmd.rs
+++ b/common/src/cmd.rs
@@ -255,9 +255,11 @@ lazy_static! {
             })
     };
 
-    static ref KITS: Vec<String> = {
+    pub static ref KITS: Vec<String> = {
         if let Ok(kits) = KitManifest::load(KIT_MANIFEST_PATH) {
-            kits.read().0.keys().cloned().collect()
+            let mut kits = kits.read().0.keys().cloned().collect::<Vec<String>>();
+            kits.sort();
+            kits
         } else {
             Vec::new()
         }
diff --git a/server/src/cmd.rs b/server/src/cmd.rs
index 3554d12ac9..a214a4baf5 100644
--- a/server/src/cmd.rs
+++ b/server/src/cmd.rs
@@ -472,7 +472,16 @@ fn handle_give_item(
         if let Ok(item) = Item::new_from_asset(&item_name.replace('/', ".").replace("\\", ".")) {
             let mut item: Item = item;
             let mut res = Ok(());
-            if let Ok(()) = item.set_amount(give_amount.min(2000)) {
+
+            const MAX_GIVE_AMOUNT: u32 = 2000;
+            // Cap give_amount for non-stackable items
+            let give_amount = if item.is_stackable() {
+                give_amount
+            } else {
+                give_amount.min(MAX_GIVE_AMOUNT)
+            };
+
+            if let Ok(()) = item.set_amount(give_amount) {
                 server
                     .state
                     .ecs()
diff --git a/voxygen/egui/Cargo.toml b/voxygen/egui/Cargo.toml
index 6c59194d8c..29b246f246 100644
--- a/voxygen/egui/Cargo.toml
+++ b/voxygen/egui/Cargo.toml
@@ -5,7 +5,7 @@ edition = "2018"
 version = "0.9.0"
 
 [features]
-use-dyn-lib = ["lazy_static", "voxygen-dynlib"]
+use-dyn-lib = ["voxygen-dynlib"]
 be-dyn-lib = []
 
 [dependencies]
@@ -13,8 +13,7 @@ client = {package = "veloren-client", path = "../../client"}
 common = {package = "veloren-common", path = "../../common"}
 egui = "0.12"
 egui_winit_platform = "0.8"
+lazy_static = "1.4.0"
 voxygen-dynlib = {package = "veloren-voxygen-dynlib", path = "../dynlib", optional = true}
 
-# Hot Reloading
-lazy_static = {version = "1.4.0", optional = true}
 
diff --git a/voxygen/egui/src/admin.rs b/voxygen/egui/src/admin.rs
new file mode 100644
index 0000000000..73b365321b
--- /dev/null
+++ b/voxygen/egui/src/admin.rs
@@ -0,0 +1,94 @@
+use crate::{AdminCommandState, EguiAction, EguiActions, EguiWindows};
+use common::cmd::ChatCommand;
+use egui::{CollapsingHeader, CtxRef, Resize, Slider, Ui, Vec2, Window};
+use lazy_static::lazy_static;
+
+lazy_static! {
+    static ref ITEM_SPECS: Vec<String> = {
+        let mut item_specs = common::cmd::ITEM_SPECS
+            .iter()
+            .map(|item_desc| item_desc.replace("common.items.", ""))
+            .collect::<Vec<String>>();
+        item_specs.sort();
+        item_specs
+    };
+}
+
+pub fn draw_admin_commands_window(
+    ctx: &CtxRef,
+    state: &mut AdminCommandState,
+    windows: &mut EguiWindows,
+    egui_actions: &mut EguiActions,
+) {
+    Window::new("Admin Commands")
+        .open(&mut windows.admin_commands)
+        .default_width(400.0)
+        .default_height(600.0)
+        .show(ctx, |ui| {
+            ui.spacing_mut().item_spacing = Vec2::new(10.0, 10.0);
+            ui.vertical(|ui| {
+                CollapsingHeader::new("Give Items")
+                    .default_open(true)
+                    .show(ui, |ui| {
+                        draw_give_items(ui, state, egui_actions);
+                    });
+                CollapsingHeader::new("Kits")
+                    .default_open(false)
+                    .show(ui, |ui| {
+                        draw_kits(ui, state, egui_actions);
+                    });
+            });
+        });
+}
+
+fn draw_kits(ui: &mut Ui, state: &mut AdminCommandState, egui_actions: &mut EguiActions) {
+    ui.vertical(|ui| {
+        if ui.button("Give Kit").clicked() {
+            egui_actions.actions.push(EguiAction::ChatCommand {
+                cmd: ChatCommand::Kit,
+                args: vec![common::cmd::KITS[state.kits_selected_idx].clone()],
+            });
+        };
+        crate::widgets::filterable_list(ui, &common::cmd::KITS, "", &mut state.kits_selected_idx)
+    });
+}
+
+fn draw_give_items(ui: &mut Ui, state: &mut AdminCommandState, egui_actions: &mut EguiActions) {
+    ui.spacing_mut().window_padding = Vec2::new(10.0, 10.0);
+    Resize::default()
+        .default_size([400.0, 200.0])
+        .show(ui, |ui| {
+            ui.horizontal(|ui| {
+                ui.add(
+                    Slider::new(&mut state.give_item_qty, 1..=100000)
+                        .logarithmic(true)
+                        .clamp_to_range(true)
+                        .text("Qty"),
+                );
+                if ui.button("Give Items").clicked() {
+                    egui_actions.actions.push(EguiAction::ChatCommand {
+                        cmd: ChatCommand::GiveItem,
+                        args: vec![
+                            format!(
+                                "common.items.{}",
+                                ITEM_SPECS[state.give_item_selected_idx].clone()
+                            ),
+                            format!("{}", state.give_item_qty),
+                        ],
+                    });
+                };
+            });
+            ui.horizontal(|ui| {
+                ui.label("Filter:");
+
+                ui.text_edit_singleline(&mut state.give_item_search_text);
+            });
+
+            crate::widgets::filterable_list(
+                ui,
+                &ITEM_SPECS,
+                &state.give_item_search_text,
+                &mut state.give_item_selected_idx,
+            );
+        });
+}
diff --git a/voxygen/egui/src/character_states.rs b/voxygen/egui/src/character_states.rs
index 39a8660119..d27a8975cc 100644
--- a/voxygen/egui/src/character_states.rs
+++ b/voxygen/egui/src/character_states.rs
@@ -1,4 +1,4 @@
-use crate::{two_col_row, SelectedEntityInfo};
+use crate::{widgets::two_col_row, SelectedEntityInfo};
 use common::{
     comp::CharacterState,
     states::{charged_melee, combo_melee, dash_melee, leap_melee},
diff --git a/voxygen/egui/src/lib.rs b/voxygen/egui/src/lib.rs
index 7acf8a3f0b..74636be28e 100644
--- a/voxygen/egui/src/lib.rs
+++ b/voxygen/egui/src/lib.rs
@@ -3,7 +3,9 @@
 #[cfg(all(feature = "be-dyn-lib", feature = "use-dyn-lib"))]
 compile_error!("Can't use both \"be-dyn-lib\" and \"use-dyn-lib\" features at once");
 
+mod admin;
 mod character_states;
+mod widgets;
 
 use client::{Client, Join, World, WorldExt};
 use common::{
@@ -14,17 +16,17 @@ use core::mem;
 use egui::{
     plot::{Plot, Value},
     widgets::plot::Curve,
-    CollapsingHeader, Color32, Grid, Label, Pos2, ScrollArea, Slider, Ui, Window,
+    CollapsingHeader, Color32, Grid, Pos2, ScrollArea, Slider, Ui, Window,
 };
 
-fn two_col_row(ui: &mut Ui, label: impl Into<Label>, content: impl Into<Label>) {
-    ui.label(label);
-    ui.label(content);
-    ui.end_row();
-}
-
-use crate::character_states::draw_char_state_group;
-use common::comp::{aura::AuraKind::Buff, Body, Fluid};
+use crate::{
+    admin::draw_admin_commands_window, character_states::draw_char_state_group,
+    widgets::two_col_row,
+};
+use common::{
+    cmd::ChatCommand,
+    comp::{aura::AuraKind::Buff, Body, Fluid},
+};
 use egui_winit_platform::Platform;
 use std::time::Duration;
 #[cfg(feature = "use-dyn-lib")]
@@ -58,6 +60,24 @@ impl SelectedEntityInfo {
     }
 }
 
+pub struct AdminCommandState {
+    give_item_qty: u32,
+    give_item_selected_idx: usize,
+    give_item_search_text: String,
+    kits_selected_idx: usize,
+}
+
+impl AdminCommandState {
+    fn new() -> Self {
+        Self {
+            give_item_qty: 1,
+            give_item_selected_idx: 0,
+            give_item_search_text: String::new(),
+            kits_selected_idx: 0,
+        }
+    }
+}
+
 pub struct EguiDebugInfo {
     pub frame_time: Duration,
     pub ping_ms: f64,
@@ -65,13 +85,16 @@ pub struct EguiDebugInfo {
 
 pub struct EguiInnerState {
     selected_entity_info: Option<SelectedEntityInfo>,
+    admin_command_state: AdminCommandState,
     max_entity_distance: f32,
     selected_entity_cylinder_height: f32,
     frame_times: Vec<f32>,
+    windows: EguiWindows,
 }
 
 #[derive(Clone, Default)]
 pub struct EguiWindows {
+    admin_commands: bool,
     egui_inspection: bool,
     egui_settings: bool,
     egui_memory: bool,
@@ -82,15 +105,17 @@ pub struct EguiWindows {
 impl Default for EguiInnerState {
     fn default() -> Self {
         Self {
+            admin_command_state: AdminCommandState::new(),
             selected_entity_info: None,
             max_entity_distance: 100000.0,
             selected_entity_cylinder_height: 10.0,
             frame_times: Vec::new(),
+            windows: EguiWindows::default(),
         }
     }
 }
 
-pub enum DebugShapeAction {
+pub enum EguiDebugShapeAction {
     AddCylinder {
         radius: f32,
         height: f32,
@@ -103,9 +128,14 @@ pub enum DebugShapeAction {
     },
 }
 
+pub enum EguiAction {
+    ChatCommand { cmd: ChatCommand, args: Vec<String> },
+    DebugShape(EguiDebugShapeAction),
+}
+
 #[derive(Default)]
 pub struct EguiActions {
-    pub actions: Vec<DebugShapeAction>,
+    pub actions: Vec<EguiAction>,
 }
 
 #[cfg(feature = "use-dyn-lib")]
@@ -114,7 +144,6 @@ pub fn init() { lazy_static::initialize(&LIB); }
 pub fn maintain(
     platform: &mut Platform,
     egui_state: &mut EguiInnerState,
-    egui_windows: &mut EguiWindows,
     client: &Client,
     debug_info: Option<EguiDebugInfo>,
     added_cylinder_shape_id: Option<u64>,
@@ -124,7 +153,6 @@ pub fn maintain(
         maintain_egui_inner(
             platform,
             egui_state,
-            egui_windows,
             client,
             debug_info,
             added_cylinder_shape_id,
@@ -141,7 +169,6 @@ pub fn maintain(
             fn(
                 &mut Platform,
                 &mut EguiInnerState,
-                &mut EguiWindows,
                 &Client,
                 Option<EguiDebugInfo>,
                 Option<u64>,
@@ -160,7 +187,6 @@ pub fn maintain(
         maintain_fn(
             platform,
             egui_state,
-            egui_windows,
             client,
             debug_info,
             added_cylinder_shape_id,
@@ -172,7 +198,6 @@ pub fn maintain(
 pub fn maintain_egui_inner(
     platform: &mut Platform,
     egui_state: &mut EguiInnerState,
-    egui_windows: &mut EguiWindows,
     client: &Client,
     debug_info: Option<EguiDebugInfo>,
     added_cylinder_shape_id: Option<u64>,
@@ -184,6 +209,7 @@ pub fn maintain_egui_inner(
     let mut previous_selected_entity: Option<SelectedEntityInfo> = None;
     let mut max_entity_distance = egui_state.max_entity_distance;
     let mut selected_entity_cylinder_height = egui_state.selected_entity_cylinder_height;
+    let mut windows = egui_state.windows.clone();
 
     // If a debug cylinder was added in the last frame, store it against the
     // selected entity
@@ -216,8 +242,9 @@ pub fn maintain_egui_inner(
             });
             ui.group(|ui| {
                 ui.vertical(|ui| {
-                    ui.checkbox(&mut egui_windows.ecs_entities, "ECS Entities");
-                    ui.checkbox(&mut egui_windows.frame_time, "Frame Time");
+                    ui.checkbox(&mut windows.admin_commands, "Admin Commands");
+                    ui.checkbox(&mut windows.ecs_entities, "ECS Entities");
+                    ui.checkbox(&mut windows.frame_time, "Frame Time");
                 });
             });
 
@@ -225,36 +252,36 @@ pub fn maintain_egui_inner(
                 ui.vertical(|ui| {
                     ui.label("Show EGUI Windows");
                     ui.horizontal(|ui| {
-                        ui.checkbox(&mut egui_windows.egui_inspection, "🔍 Inspection");
-                        ui.checkbox(&mut egui_windows.egui_settings, "🔧 Settings");
-                        ui.checkbox(&mut egui_windows.egui_memory, "📝 Memory");
+                        ui.checkbox(&mut windows.egui_inspection, "🔍 Inspection");
+                        ui.checkbox(&mut windows.egui_settings, "🔧 Settings");
+                        ui.checkbox(&mut windows.egui_memory, "📝 Memory");
                     })
                 })
             });
         });
 
     Window::new("🔧 Settings")
-        .open(&mut egui_windows.egui_settings)
+        .open(&mut windows.egui_settings)
         .scroll(true)
         .show(ctx, |ui| {
             ctx.settings_ui(ui);
         });
     Window::new("🔍 Inspection")
-        .open(&mut egui_windows.egui_inspection)
+        .open(&mut windows.egui_inspection)
         .scroll(true)
         .show(ctx, |ui| {
             ctx.inspection_ui(ui);
         });
 
     Window::new("📝 Memory")
-        .open(&mut egui_windows.egui_memory)
+        .open(&mut windows.egui_memory)
         .resizable(false)
         .show(ctx, |ui| {
             ctx.memory_ui(ui);
         });
 
     Window::new("Frame Time")
-        .open(&mut egui_windows.frame_time)
+        .open(&mut windows.frame_time)
         .default_width(200.0)
         .default_height(200.0)
         .show(ctx, |ui| {
@@ -268,14 +295,14 @@ pub fn maintain_egui_inner(
             ui.add(plot);
         });
 
-    if egui_windows.ecs_entities {
+    if windows.ecs_entities {
         let ecs = client.state().ecs();
 
         let positions = client.state().ecs().read_storage::<comp::Pos>();
         let client_pos = positions.get(client.entity());
 
         egui::Window::new("ECS Entities")
-            .open(&mut egui_windows.ecs_entities)
+            .open(&mut windows.ecs_entities)
             .default_width(500.0)
             .default_height(500.0)
             .show(ctx, |ui| {
@@ -333,10 +360,12 @@ pub fn maintain_egui_inner(
                                         mem::take(&mut egui_state.selected_entity_info);
 
                                     if pos.is_some() {
-                                        egui_actions.actions.push(DebugShapeAction::AddCylinder {
-                                            radius: 1.0,
-                                            height: egui_state.selected_entity_cylinder_height,
-                                        });
+                                        egui_actions.actions.push(EguiAction::DebugShape(
+                                            EguiDebugShapeAction::AddCylinder {
+                                                radius: 1.0,
+                                                height: egui_state.selected_entity_cylinder_height,
+                                            },
+                                        ));
                                     }
                                     egui_state.selected_entity_info =
                                         Some(SelectedEntityInfo::new(entity.id()));
@@ -403,11 +432,20 @@ pub fn maintain_egui_inner(
         }
     }
 
+    draw_admin_commands_window(
+        ctx,
+        &mut egui_state.admin_command_state,
+        &mut windows,
+        &mut egui_actions,
+    );
+
     if let Some(previous) = previous_selected_entity {
         if let Some(debug_shape_id) = previous.debug_shape_id {
             egui_actions
                 .actions
-                .push(DebugShapeAction::RemoveShape(debug_shape_id));
+                .push(EguiAction::DebugShape(EguiDebugShapeAction::RemoveShape(
+                    debug_shape_id,
+                )));
         }
     };
 
@@ -416,19 +454,22 @@ pub fn maintain_egui_inner(
             if (egui_state.selected_entity_cylinder_height - selected_entity_cylinder_height).abs()
                 > f32::EPSILON
             {
-                egui_actions
-                    .actions
-                    .push(DebugShapeAction::RemoveShape(debug_shape_id));
-                egui_actions.actions.push(DebugShapeAction::AddCylinder {
-                    radius: 1.0,
-                    height: selected_entity_cylinder_height,
-                });
+                egui_actions.actions.push(EguiAction::DebugShape(
+                    EguiDebugShapeAction::RemoveShape(debug_shape_id),
+                ));
+                egui_actions.actions.push(EguiAction::DebugShape(
+                    EguiDebugShapeAction::AddCylinder {
+                        radius: 1.0,
+                        height: selected_entity_cylinder_height,
+                    },
+                ));
             }
         }
     };
 
     egui_state.max_entity_distance = max_entity_distance;
     egui_state.selected_entity_cylinder_height = selected_entity_cylinder_height;
+    egui_state.windows = windows;
     egui_actions
 }
 
@@ -481,11 +522,13 @@ fn selected_entity_window(
     {
         if let Some(pos) = pos {
             if let Some(shape_id) = selected_entity_info.debug_shape_id {
-                egui_actions.actions.push(DebugShapeAction::SetPosAndColor {
-                    id: shape_id,
-                    color: [1.0, 1.0, 0.0, 0.5],
-                    pos: [pos.0.x, pos.0.y, pos.0.z + 2.0, 0.0],
-                });
+                egui_actions.actions.push(EguiAction::DebugShape(
+                    EguiDebugShapeAction::SetPosAndColor {
+                        id: shape_id,
+                        color: [1.0, 1.0, 0.0, 0.5],
+                        pos: [pos.0.x, pos.0.y, pos.0.z + 2.0, 0.0],
+                    },
+                ));
             }
         };
 
diff --git a/voxygen/egui/src/widgets.rs b/voxygen/egui/src/widgets.rs
new file mode 100644
index 0000000000..8cde109367
--- /dev/null
+++ b/voxygen/egui/src/widgets.rs
@@ -0,0 +1,34 @@
+use egui::{Label, ScrollArea, Ui, Vec2};
+
+pub(crate) fn filterable_list(
+    ui: &mut Ui,
+    list_items: &[String],
+    search_text: &str,
+    selected_index: &mut usize,
+) {
+    let scroll_area = ScrollArea::auto_sized();
+    scroll_area.show(ui, |ui| {
+        ui.spacing_mut().item_spacing = Vec2::new(0.0, 2.0);
+        let search_text = search_text.to_lowercase();
+        for (i, list_item) in list_items.iter().enumerate().filter_map(|(i, list_item)| {
+            if search_text.is_empty() || list_item.to_lowercase().contains(&search_text) {
+                Some((i, list_item))
+            } else {
+                None
+            }
+        }) {
+            if ui
+                .selectable_label(i == *selected_index, list_item)
+                .clicked()
+            {
+                *selected_index = i;
+            };
+        }
+    });
+}
+
+pub(crate) fn two_col_row(ui: &mut Ui, label: impl Into<Label>, content: impl Into<Label>) {
+    ui.label(label);
+    ui.label(content);
+    ui.end_row();
+}
diff --git a/voxygen/src/run.rs b/voxygen/src/run.rs
index 2a3627820e..3549e48128 100644
--- a/voxygen/src/run.rs
+++ b/voxygen/src/run.rs
@@ -32,7 +32,13 @@ pub fn run(mut global_state: GlobalState, event_loop: EventLoop) {
         *control_flow = winit::event_loop::ControlFlow::Poll;
 
         #[cfg(feature = "egui-ui")]
-        global_state.egui_state.platform.handle_event(&event);
+        {
+            global_state.egui_state.platform.handle_event(&event);
+            if global_state.egui_state.platform.captures_event(&event) {
+                return;
+            }
+        }
+
         // Get events for the ui.
         if let Some(event) = ui::Event::try_from(&event, global_state.window.window()) {
             global_state.window.send_event(Event::Ui(event));
diff --git a/voxygen/src/session/mod.rs b/voxygen/src/session/mod.rs
index 6e39ff8504..3907d616c9 100644
--- a/voxygen/src/session/mod.rs
+++ b/voxygen/src/session/mod.rs
@@ -1091,7 +1091,7 @@ impl PlayState for SessionState {
             #[cfg(feature = "egui-ui")]
             if global_state.settings.interface.egui_enabled() {
                 global_state.egui_state.maintain(
-                    &self.client.borrow(),
+                    &mut self.client.borrow_mut(),
                     &mut self.scene,
                     debug_info.map(|debug_info| EguiDebugInfo {
                         frame_time: debug_info.frame_time,
diff --git a/voxygen/src/ui/egui/mod.rs b/voxygen/src/ui/egui/mod.rs
index 47dab5aa33..e98db48f5b 100644
--- a/voxygen/src/ui/egui/mod.rs
+++ b/voxygen/src/ui/egui/mod.rs
@@ -5,12 +5,11 @@ use crate::{
 use client::Client;
 use egui::FontDefinitions;
 use egui_winit_platform::{Platform, PlatformDescriptor};
-use voxygen_egui::{DebugShapeAction, EguiDebugInfo, EguiInnerState, EguiWindows};
+use voxygen_egui::{EguiAction, EguiDebugInfo, EguiDebugShapeAction, EguiInnerState};
 
 pub struct EguiState {
     pub platform: Platform,
     egui_inner_state: EguiInnerState,
-    egui_windows: EguiWindows,
     new_debug_shape_id: Option<u64>,
 }
 
@@ -27,43 +26,48 @@ impl EguiState {
         Self {
             platform,
             egui_inner_state: EguiInnerState::default(),
-            egui_windows: EguiWindows::default(),
             new_debug_shape_id: None,
         }
     }
 
     pub fn maintain(
         &mut self,
-        client: &Client,
+        client: &mut Client,
         scene: &mut Scene,
         debug_info: Option<EguiDebugInfo>,
     ) {
         let egui_actions = voxygen_egui::maintain(
             &mut self.platform,
             &mut self.egui_inner_state,
-            &mut self.egui_windows,
             client,
             debug_info,
             self.new_debug_shape_id.take(),
         );
 
-        egui_actions.actions.iter().for_each(|action| match action {
-            DebugShapeAction::AddCylinder { height, radius } => {
-                let shape_id = scene.debug.add_shape(DebugShape::Cylinder {
-                    height: *height,
-                    radius: *radius,
-                });
-                self.new_debug_shape_id = Some(shape_id.0);
-            },
-            DebugShapeAction::RemoveShape(debug_shape_id) => {
-                scene.debug.remove_shape(DebugShapeId(*debug_shape_id));
-            },
-            DebugShapeAction::SetPosAndColor { id, pos, color } => {
-                let identity_ori = [0.0, 0.0, 0.0, 1.0];
-                scene
-                    .debug
-                    .set_context(DebugShapeId(*id), *pos, *color, identity_ori);
-            },
-        })
+        egui_actions
+            .actions
+            .into_iter()
+            .for_each(|action| match action {
+                EguiAction::ChatCommand { cmd, args } => {
+                    client.send_command(cmd.keyword().into(), args);
+                },
+                EguiAction::DebugShape(debug_shape_action) => match debug_shape_action {
+                    EguiDebugShapeAction::AddCylinder { height, radius } => {
+                        let shape_id = scene
+                            .debug
+                            .add_shape(DebugShape::Cylinder { height, radius });
+                        self.new_debug_shape_id = Some(shape_id.0);
+                    },
+                    EguiDebugShapeAction::RemoveShape(debug_shape_id) => {
+                        scene.debug.remove_shape(DebugShapeId(debug_shape_id));
+                    },
+                    EguiDebugShapeAction::SetPosAndColor { id, pos, color } => {
+                        let identity_ori = [0.0, 0.0, 0.0, 1.0];
+                        scene
+                            .debug
+                            .set_context(DebugShapeId(id), pos, color, identity_ori);
+                    },
+                },
+            })
     }
 }