diff --git a/Core/src/org/sleuthkit/autopsy/images/yara_32.png b/Core/src/org/sleuthkit/autopsy/images/yara_32.png
new file mode 100755
index 0000000000000000000000000000000000000000..9fdb23052ae46848f37fd292391c7b9244e35455
Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/images/yara_32.png differ
diff --git a/Core/src/org/sleuthkit/autopsy/modules/yara/rules/RuleSet.java b/Core/src/org/sleuthkit/autopsy/modules/yara/rules/RuleSet.java
new file mode 100755
index 0000000000000000000000000000000000000000..12b383894428703f15938fcde11e518aa20a2619
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/modules/yara/rules/RuleSet.java
@@ -0,0 +1,81 @@
+/*
+ * Autopsy Forensic Browser
+ *
+ * Copyright 2020 Basis Technology Corp.
+ * Contact: carrier <at> sleuthkit <dot> org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.sleuthkit.autopsy.modules.yara.rules;
+
+import java.io.File;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Represents a yara rule set which is a collection of yara rule files.
+ */
+public class RuleSet implements Comparable<RuleSet> {
+
+    private final String name;
+    private final Path path;
+
+    /**
+     * Construct a new RuleSet.
+     *
+     * @param name Name of the rule set.
+     * @param path Directory path to the rule set.
+     */
+    RuleSet(String name, Path path) {
+        this.name = name;
+        this.path = path;
+    }
+
+    /**
+     * Returns the name of the rule set.
+     *
+     * @return Name of rule set.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Returns location if the rule set files.
+     *
+     * @return The path for this rule set.
+     */
+    public Path getPath() {
+        return path;
+    }
+
+    /**
+     * Returns a list of the rule files in this rule set.
+     *
+     * @return List of Files in current directory.
+     */
+    public List<File> getRuleFiles() {
+        return Arrays.asList(path.toFile().listFiles());
+    }
+
+    @Override
+    public String toString() {
+        return getName();
+    }
+
+    @Override
+    public int compareTo(RuleSet ruleSet) {
+        return getName().compareTo(ruleSet.getName());
+    }
+}
diff --git a/Core/src/org/sleuthkit/autopsy/modules/yara/rules/RuleSetException.java b/Core/src/org/sleuthkit/autopsy/modules/yara/rules/RuleSetException.java
new file mode 100755
index 0000000000000000000000000000000000000000..7ae0e12c45570dd77d2022fe394b97c3c80aa418
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/modules/yara/rules/RuleSetException.java
@@ -0,0 +1,47 @@
+/*
+ * Autopsy Forensic Browser
+ *
+ * Copyright 2020 Basis Technology Corp.
+ * Contact: carrier <at> sleuthkit <dot> org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.sleuthkit.autopsy.modules.yara.rules;
+
+/**
+ *
+ * An exception class for yara rule sets.
+ */
+public class RuleSetException extends Exception {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * Construct a RuleSetException with the given message.
+     *
+     * @param msg Exception message.
+     */
+    RuleSetException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Construct a RuleSetException with the given message and exception.
+     *
+     * @param msg Exception message.
+     * @param ex  Exception.
+     */
+    RuleSetException(String msg, Exception ex) {
+        super(msg, ex);
+    }
+}
diff --git a/Core/src/org/sleuthkit/autopsy/modules/yara/rules/RuleSetManager.java b/Core/src/org/sleuthkit/autopsy/modules/yara/rules/RuleSetManager.java
new file mode 100755
index 0000000000000000000000000000000000000000..eab2f8081928e90f1b371e03c9cdae08e6365086
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/modules/yara/rules/RuleSetManager.java
@@ -0,0 +1,109 @@
+/*
+ * Autopsy Forensic Browser
+ *
+ * Copyright 2011-2020 Basis Technology Corp.
+ * Contact: carrier <at> sleuthkit <dot> org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.sleuthkit.autopsy.modules.yara.rules;
+
+import java.io.File;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import org.sleuthkit.autopsy.coreutils.PlatformUtil;
+
+/**
+ *
+ * Yara Rule Set Manager. Manages the creation, deletion of yara rule sets.
+ */
+public class RuleSetManager {
+
+    private final static String BASE_FOLDER = "yara";
+    private final static String RULE_SET_FOLDER = "ruleSets";
+
+    /**
+     * Create a new Yara rule set with the given set name.
+     *
+     * @param name Name of new rule set
+     *
+     * @return Newly created RuleSet
+     *
+     * @throws RuleSetException RuleSet with given name already exists.
+     */
+    public RuleSet createRuleSet(String name) throws RuleSetException {
+
+        if (isRuleSetExists(name)) {
+            throw new RuleSetException(String.format("Yara rule set with name %s already exits.", name));
+        }
+
+        Path basePath = getRuleSetPath();
+        Path setPath = Paths.get(basePath.toString(), name);
+
+        setPath.toFile().mkdir();
+
+        return new RuleSet(name, setPath);
+    }
+
+    /**
+     * Returns a list of all of the existing yara rule sets.
+     *
+     * @return
+     */
+    public List<RuleSet> getRuleSetList() {
+        List<RuleSet> ruleSets = new ArrayList<>();
+        Path basePath = getRuleSetPath();
+
+        String[] ruleSetNames = basePath.toFile().list();
+
+        for (String setName : ruleSetNames) {
+            ruleSets.add(new RuleSet(setName, Paths.get(basePath.toString(), setName)));
+        }
+
+        return ruleSets;
+    }
+
+    /**
+     * Check if a yara rule set of the given name exists.
+     *
+     * @param name Yara rule set name
+     *
+     * @return True if the rule set exist.
+     */
+    public boolean isRuleSetExists(String name) {
+        Path basePath = getRuleSetPath();
+        Path setPath = Paths.get(basePath.toString(), name);
+
+        return setPath.toFile().exists();
+    }
+
+    /**
+     * Returns the Path to get RuleSet directory. If it does not exist it is
+     * created.
+     *
+     * @return Yara rule set directory path.
+     */
+    private Path getRuleSetPath() {
+        Path basePath = Paths.get(PlatformUtil.getUserDirectory().getAbsolutePath(), BASE_FOLDER, RULE_SET_FOLDER);
+        File baseFile = basePath.toFile();
+
+        if (!baseFile.exists()) {
+            baseFile.mkdirs();
+        }
+
+        return basePath;
+    }
+
+}
diff --git a/Core/src/org/sleuthkit/autopsy/modules/yara/ui/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/yara/ui/Bundle.properties
new file mode 100755
index 0000000000000000000000000000000000000000..5012f855b42dba159465977d5afb4cb7a3e9efaf
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/modules/yara/ui/Bundle.properties
@@ -0,0 +1,10 @@
+OptionCategory_Name_YaraRuleSetOption=Yara Rule Sets
+OptionCategory_Keywords_YaraRuleSetOption=YaraRuleSets
+RuleSetPanel.newButton.text=New Set
+RuleSetPanel.deleteButton.text=Delete Set
+RuleSetPanel.ruleSetListLabel.text=Rule Sets:
+RuleSetDetailsPanel.ruleSetListLabel.text=The folder currently contains the following rule files:
+RuleSetDetailsPanel.setDetailsLabel.text=Set Details
+RuleSetDetailsPanel.openFolderButton.text=Open Folder
+RuleSetPanel.descriptionField.text=This module allows you to find files the match Yara rules. Each set has a list of Yara rule files.  A file need only match one rule in the set to be found.
+RuleSetDetailsPanel.openLabel.text=Place rule files in the set's folder. They will be compiled before use.
diff --git a/Core/src/org/sleuthkit/autopsy/modules/yara/ui/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/modules/yara/ui/Bundle.properties-MERGED
new file mode 100755
index 0000000000000000000000000000000000000000..a6b64a97c0cdb6b37cdd35efe706d5a6b53f855f
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/modules/yara/ui/Bundle.properties-MERGED
@@ -0,0 +1,17 @@
+OptionCategory_Name_YaraRuleSetOption=Yara Rule Sets
+OptionCategory_Keywords_YaraRuleSetOption=YaraRuleSets
+RuleSetDetailsPanel_failed_to_open_folder_msg=Failed to open new window for rule set file.
+RuleSetDetailsPanel_failed_to_open_folder_title=Open Error
+RuleSetPanel.newButton.text=New Set
+RuleSetPanel.deleteButton.text=Delete Set
+RuleSetPanel.ruleSetListLabel.text=Rule Sets:
+RuleSetDetailsPanel.ruleSetListLabel.text=The folder currently contains the following rule files:
+RuleSetDetailsPanel.setDetailsLabel.text=Set Details
+RuleSetDetailsPanel.openFolderButton.text=Open Folder
+RuleSetPanel.descriptionField.text=This module allows you to find files the match Yara rules. Each set has a list of Yara rule files.  A file need only match one rule in the set to be found.
+RuleSetDetailsPanel.openLabel.text=Place rule files in the set's folder. They will be compiled before use.
+# {0} - rule set name
+YaraRuleSetOptionPanel_badName_msg=Rule set name {0} already exists.\nRule set names must be unique.
+YaraRuleSetOptionPanel_badName_title=Create Rule Set
+YaraRuleSetOptionPanel_new_rule_set_name_msg=Supply a new unique rule set name:
+YaraRuleSetOptionPanel_new_rule_set_name_title=Rule Set Name
diff --git a/Core/src/org/sleuthkit/autopsy/modules/yara/ui/RuleSetDetailsPanel.form b/Core/src/org/sleuthkit/autopsy/modules/yara/ui/RuleSetDetailsPanel.form
new file mode 100755
index 0000000000000000000000000000000000000000..2f1c87a69fbe23684c927a52a58558ffc77c68f8
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/modules/yara/ui/RuleSetDetailsPanel.form
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+    <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,2,-85"/>
+  </AuxValues>
+
+  <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
+  <SubComponents>
+    <Component class="javax.swing.JLabel" name="ruleSetListLabel">
+      <Properties>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="org/sleuthkit/autopsy/modules/yara/ui/Bundle.properties" key="RuleSetDetailsPanel.ruleSetListLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+      </Properties>
+      <AuxValues>
+        <AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
+        <AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
+      </AuxValues>
+      <Constraints>
+        <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
+          <GridBagConstraints gridX="0" gridY="3" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="16" insetsLeft="0" insetsBottom="3" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/>
+        </Constraint>
+      </Constraints>
+    </Component>
+    <Component class="javax.swing.JLabel" name="setDetailsLabel">
+      <Properties>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="org/sleuthkit/autopsy/modules/yara/ui/Bundle.properties" key="RuleSetDetailsPanel.setDetailsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+      </Properties>
+      <AuxValues>
+        <AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
+        <AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
+      </AuxValues>
+      <Constraints>
+        <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
+          <GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="10" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/>
+        </Constraint>
+      </Constraints>
+    </Component>
+    <Component class="javax.swing.JButton" name="openFolderButton">
+      <Properties>
+        <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
+          <Image iconType="3" name="/org/sleuthkit/autopsy/images/folder-icon-16.png"/>
+        </Property>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="org/sleuthkit/autopsy/modules/yara/ui/Bundle.properties" key="RuleSetDetailsPanel.openFolderButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="openFolderButtonActionPerformed"/>
+      </Events>
+      <Constraints>
+        <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
+          <GridBagConstraints gridX="1" gridY="5" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="10" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/>
+        </Constraint>
+      </Constraints>
+    </Component>
+    <Component class="javax.swing.JLabel" name="openLabel">
+      <Properties>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="org/sleuthkit/autopsy/modules/yara/ui/Bundle.properties" key="RuleSetDetailsPanel.openLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+      </Properties>
+      <Constraints>
+        <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
+          <GridBagConstraints gridX="0" gridY="5" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="10" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/>
+        </Constraint>
+      </Constraints>
+    </Component>
+    <Container class="javax.swing.JScrollPane" name="scrollPane">
+      <Constraints>
+        <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
+          <GridBagConstraints gridX="0" gridY="4" gridWidth="2" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="5" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="1.0" weightY="1.0"/>
+        </Constraint>
+      </Constraints>
+
+      <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+    </Container>
+  </SubComponents>
+</Form>
diff --git a/Core/src/org/sleuthkit/autopsy/modules/yara/ui/RuleSetDetailsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/yara/ui/RuleSetDetailsPanel.java
new file mode 100755
index 0000000000000000000000000000000000000000..8c284a190e10a40eb25955b4924ef6197f24a742
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/modules/yara/ui/RuleSetDetailsPanel.java
@@ -0,0 +1,197 @@
+/*
+ * Autopsy Forensic Browser
+ *
+ * Copyright 2020 Basis Technology Corp.
+ * Contact: carrier <at> sleuthkit <dot> org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.sleuthkit.autopsy.modules.yara.ui;
+
+import java.awt.Component;
+import java.awt.Desktop;
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.DefaultListModel;
+import javax.swing.JList;
+import javax.swing.JOptionPane;
+import org.openide.util.NbBundle.Messages;
+import org.sleuthkit.autopsy.modules.yara.rules.RuleSet;
+
+/**
+ * A panel for displaying the details of an individual yara rule set.
+ */
+public class RuleSetDetailsPanel extends javax.swing.JPanel {
+
+    private static final long serialVersionUID = 1L;
+
+    private static final Logger logger = Logger.getLogger(RuleSetDetailsPanel.class.getName());
+
+    private RuleSet currentRuleSet;
+    private final DefaultListModel<File> fileListModel;
+    private final JList<File> fileList;
+
+    /**
+     * Creates new form RuleSetDetailsPanel
+     */
+    public RuleSetDetailsPanel() {
+        initComponents();
+
+        fileListModel = new DefaultListModel<>();
+        fileList = new JList<>();
+        fileList.setModel(fileListModel);
+        fileList.setCellRenderer(new FileRenderer());
+        openFolderButton.setEnabled(false);
+
+    }
+
+    /**
+     * Update the panel to show the details of the given RuleSet.
+     *
+     * @param ruleSet New RuleSet to display
+     */
+    void setRuleSet(RuleSet ruleSet) {
+        currentRuleSet = ruleSet;
+
+        fileListModel.clear();
+
+        if (ruleSet != null) {
+            List<File> files = currentRuleSet.getRuleFiles();
+
+            for (File file : files) {
+                fileListModel.addElement(file);
+            }
+        }
+
+        openFolderButton.setEnabled(ruleSet != null);
+    }
+
+    /**
+     * Simple ListCellRenderer for the file list.
+     */
+    private final class FileRenderer extends DefaultListCellRenderer {
+
+        private static final long serialVersionUID = 1L;
+
+        @Override
+        public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+            super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
+
+            if (value instanceof File) {
+                File file = (File) value;
+                setText(file.getName());
+                setToolTipText(file.getAbsolutePath());
+            }
+
+            return this;
+        }
+    }
+
+    /**
+     * This method is called from within the constructor to initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is always
+     * regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+        java.awt.GridBagConstraints gridBagConstraints;
+
+        javax.swing.JLabel ruleSetListLabel = new javax.swing.JLabel();
+        javax.swing.JLabel setDetailsLabel = new javax.swing.JLabel();
+        openFolderButton = new javax.swing.JButton();
+        openLabel = new javax.swing.JLabel();
+        scrollPane = new javax.swing.JScrollPane();
+
+        setLayout(new java.awt.GridBagLayout());
+
+        org.openide.awt.Mnemonics.setLocalizedText(ruleSetListLabel, org.openide.util.NbBundle.getMessage(RuleSetDetailsPanel.class, "RuleSetDetailsPanel.ruleSetListLabel.text")); // NOI18N
+        gridBagConstraints = new java.awt.GridBagConstraints();
+        gridBagConstraints.gridx = 0;
+        gridBagConstraints.gridy = 3;
+        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
+        gridBagConstraints.insets = new java.awt.Insets(16, 0, 3, 0);
+        add(ruleSetListLabel, gridBagConstraints);
+
+        org.openide.awt.Mnemonics.setLocalizedText(setDetailsLabel, org.openide.util.NbBundle.getMessage(RuleSetDetailsPanel.class, "RuleSetDetailsPanel.setDetailsLabel.text")); // NOI18N
+        gridBagConstraints = new java.awt.GridBagConstraints();
+        gridBagConstraints.gridx = 0;
+        gridBagConstraints.gridy = 0;
+        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
+        gridBagConstraints.insets = new java.awt.Insets(0, 0, 10, 0);
+        add(setDetailsLabel, gridBagConstraints);
+
+        openFolderButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/folder-icon-16.png"))); // NOI18N
+        org.openide.awt.Mnemonics.setLocalizedText(openFolderButton, org.openide.util.NbBundle.getMessage(RuleSetDetailsPanel.class, "RuleSetDetailsPanel.openFolderButton.text")); // NOI18N
+        openFolderButton.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                openFolderButtonActionPerformed(evt);
+            }
+        });
+        gridBagConstraints = new java.awt.GridBagConstraints();
+        gridBagConstraints.gridx = 1;
+        gridBagConstraints.gridy = 5;
+        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
+        gridBagConstraints.insets = new java.awt.Insets(10, 0, 0, 0);
+        add(openFolderButton, gridBagConstraints);
+
+        org.openide.awt.Mnemonics.setLocalizedText(openLabel, org.openide.util.NbBundle.getMessage(RuleSetDetailsPanel.class, "RuleSetDetailsPanel.openLabel.text")); // NOI18N
+        gridBagConstraints = new java.awt.GridBagConstraints();
+        gridBagConstraints.gridx = 0;
+        gridBagConstraints.gridy = 5;
+        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
+        gridBagConstraints.insets = new java.awt.Insets(10, 0, 0, 0);
+        add(openLabel, gridBagConstraints);
+        gridBagConstraints = new java.awt.GridBagConstraints();
+        gridBagConstraints.gridx = 0;
+        gridBagConstraints.gridy = 4;
+        gridBagConstraints.gridwidth = 2;
+        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
+        gridBagConstraints.weightx = 1.0;
+        gridBagConstraints.weighty = 1.0;
+        gridBagConstraints.insets = new java.awt.Insets(5, 0, 0, 0);
+        add(scrollPane, gridBagConstraints);
+    }// </editor-fold>//GEN-END:initComponents
+
+    @Messages({
+        "RuleSetDetailsPanel_failed_to_open_folder_msg=Failed to open new window for rule set file.",
+        "RuleSetDetailsPanel_failed_to_open_folder_title=Open Error"
+    })
+    private void openFolderButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openFolderButtonActionPerformed
+        if (currentRuleSet != null) {
+            File file = currentRuleSet.getPath().toFile();
+            if (file.exists()) {
+                try {
+                    Desktop.getDesktop().open(file);
+                } catch (IOException ex) {
+                    JOptionPane.showMessageDialog(this,
+                            Bundle.RuleSetDetailsPanel_failed_to_open_folder_msg(),
+                            Bundle.RuleSetDetailsPanel_failed_to_open_folder_title(),
+                            JOptionPane.ERROR_MESSAGE);
+                    logger.log(Level.WARNING, String.format("Failed to open external file explorer for: %s", currentRuleSet.getPath().toString()), ex);
+                }
+            }
+        }
+    }//GEN-LAST:event_openFolderButtonActionPerformed
+
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JButton openFolderButton;
+    private javax.swing.JLabel openLabel;
+    private javax.swing.JScrollPane scrollPane;
+    // End of variables declaration//GEN-END:variables
+}
diff --git a/Core/src/org/sleuthkit/autopsy/modules/yara/ui/RuleSetPanel.form b/Core/src/org/sleuthkit/autopsy/modules/yara/ui/RuleSetPanel.form
new file mode 100755
index 0000000000000000000000000000000000000000..bd3e12390f4641d2ef0e2fea53c7b58a38eade9a
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/modules/yara/ui/RuleSetPanel.form
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+    <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,-114,0,0,1,-112"/>
+  </AuxValues>
+
+  <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
+  <SubComponents>
+    <Component class="javax.swing.JTextPane" name="descriptionField">
+      <Properties>
+        <Property name="editable" type="boolean" value="false"/>
+        <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
+          <Border info="org.netbeans.modules.form.compat2.border.LineBorderInfo">
+            <LineBorder/>
+          </Border>
+        </Property>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="org/sleuthkit/autopsy/modules/yara/ui/Bundle.properties" key="RuleSetPanel.descriptionField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+        <Property name="opaque" type="boolean" value="false"/>
+      </Properties>
+      <AuxValues>
+        <AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
+        <AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
+      </AuxValues>
+      <Constraints>
+        <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
+          <GridBagConstraints gridX="-1" gridY="-1" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="1.0" weightY="0.0"/>
+        </Constraint>
+      </Constraints>
+    </Component>
+    <Component class="javax.swing.JLabel" name="ruleSetListLabel">
+      <Properties>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="org/sleuthkit/autopsy/modules/yara/ui/Bundle.properties" key="RuleSetPanel.ruleSetListLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+      </Properties>
+      <AuxValues>
+        <AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
+        <AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
+      </AuxValues>
+      <Constraints>
+        <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
+          <GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="15" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/>
+        </Constraint>
+      </Constraints>
+    </Component>
+    <Container class="javax.swing.JScrollPane" name="scrollPane">
+      <AuxValues>
+        <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
+      </AuxValues>
+      <Constraints>
+        <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
+          <GridBagConstraints gridX="0" gridY="2" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="5" insetsLeft="0" insetsBottom="10" insetsRight="0" anchor="10" weightX="1.0" weightY="1.0"/>
+        </Constraint>
+      </Constraints>
+
+      <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+    </Container>
+    <Container class="javax.swing.JPanel" name="buttonPanel">
+      <AuxValues>
+        <AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
+        <AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
+      </AuxValues>
+      <Constraints>
+        <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
+          <GridBagConstraints gridX="0" gridY="-1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/>
+        </Constraint>
+      </Constraints>
+
+      <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridLayout">
+        <Property name="columns" type="int" value="0"/>
+        <Property name="horizontalGap" type="int" value="5"/>
+        <Property name="rows" type="int" value="1"/>
+      </Layout>
+      <SubComponents>
+        <Component class="javax.swing.JButton" name="newButton">
+          <Properties>
+            <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
+              <Image iconType="3" name="/org/sleuthkit/autopsy/images/add16.png"/>
+            </Property>
+            <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+              <ResourceString bundle="org/sleuthkit/autopsy/modules/yara/ui/Bundle.properties" key="RuleSetPanel.newButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+            </Property>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JButton" name="deleteButton">
+          <Properties>
+            <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
+              <Image iconType="3" name="/org/sleuthkit/autopsy/images/delete16.png"/>
+            </Property>
+            <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+              <ResourceString bundle="org/sleuthkit/autopsy/modules/yara/ui/Bundle.properties" key="RuleSetPanel.deleteButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+            </Property>
+          </Properties>
+        </Component>
+      </SubComponents>
+    </Container>
+  </SubComponents>
+</Form>
diff --git a/Core/src/org/sleuthkit/autopsy/modules/yara/ui/RuleSetPanel.java b/Core/src/org/sleuthkit/autopsy/modules/yara/ui/RuleSetPanel.java
new file mode 100755
index 0000000000000000000000000000000000000000..63474a8adb2a6edd56a47164e50f12c1af0c59ac
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/modules/yara/ui/RuleSetPanel.java
@@ -0,0 +1,231 @@
+/*
+ * Autopsy Forensic Browser
+ *
+ * Copyright 2020 Basis Technology Corp.
+ * Contact: carrier <at> sleuthkit <dot> org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.sleuthkit.autopsy.modules.yara.ui;
+
+import java.awt.Component;
+import java.awt.event.ActionListener;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.DefaultListModel;
+import javax.swing.JList;
+import javax.swing.ListSelectionModel;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import org.sleuthkit.autopsy.modules.yara.rules.RuleSet;
+
+/**
+ * Panel for managing yara rule sets.
+ */
+public final class RuleSetPanel extends javax.swing.JPanel {
+
+    private static final long serialVersionUID = 1L;
+
+    private final DefaultListModel<RuleSet> listModel;
+    private final JList<RuleSet> ruleSetList;
+
+    public RuleSetPanel() {
+        initComponents();
+
+        // Creating and initializing JList here to better take
+        // advantace of JList use of generics.
+        ruleSetList = new JList<>();
+        listModel = new DefaultListModel<>();
+        scrollPane.setViewportView(ruleSetList);
+        ruleSetList.setModel(listModel);
+        ruleSetList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+        ruleSetList.setCellRenderer(new RuleSetRenderer());
+        ruleSetList.addListSelectionListener(new ListSelectionListener() {
+            @Override
+            public void valueChanged(ListSelectionEvent e) {
+                deleteButton.setEnabled(getSelectedRule() != null);
+            }
+        });
+
+        deleteButton.setEnabled(false);
+    }
+
+    /**
+     * Add the list of rule sets to the list model.
+     *
+     * @param ruleSetList Rule sets to add.
+     */
+    void addSetList(List<RuleSet> newSetList) {
+        // Put the list into alphectical order.
+        List<RuleSet> list = new ArrayList<>();
+        list.addAll(newSetList);
+        Collections.sort(list);
+
+        listModel.clear();
+
+        for (RuleSet set : list) {
+            listModel.addElement(set);
+        }
+    }
+
+    /**
+     * Adds a new rule to the list.
+     *
+     * @param set
+     */
+    void addRuleSet(RuleSet set) {
+        // This will assure that the new item
+        // appears in the correct location.
+        List<RuleSet> list = Collections.list(listModel.elements());
+        list.add(set);
+
+        addSetList(list);
+
+        ruleSetList.setSelectedValue(set, true);
+    }
+
+    /**
+     * Removes a rule set from the list.
+     *
+     * @param set
+     */
+    void removeRuleSet(RuleSet set) {
+        listModel.removeElement(set);
+    }
+
+    /**
+     * Add a listener for the new rule set action.
+     *
+     * @param listener
+     */
+    void addNewRuleListener(ActionListener listener) {
+        newButton.addActionListener(listener);
+    }
+
+    /**
+     * Add a listener for the delete rule set action.
+     *
+     * @param listener
+     */
+    void addDeleteRuleListener(ActionListener listener) {
+        deleteButton.addActionListener(listener);
+    }
+
+    /**
+     * Add a listener for list selection change.
+     *
+     * @param listener
+     */
+    void addListSelectionListener(ListSelectionListener listener) {
+        ruleSetList.addListSelectionListener(listener);
+    }
+
+    /**
+     * Returns the current selected rule set.
+     *
+     * @return Currently selected rule set or null if one is not selected.
+     */
+    RuleSet getSelectedRule() {
+        return ruleSetList.getSelectedValue();
+    }
+
+    /**
+     * Simple ListCellRenderer for a RuleSet.
+     */
+    private final class RuleSetRenderer extends DefaultListCellRenderer {
+
+        private static final long serialVersionUID = 1L;
+
+        @Override
+        public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+            super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
+
+            if (value instanceof RuleSet) {
+                RuleSet set = (RuleSet) value;
+                setText(set.getName());
+                setToolTipText(set.getName());
+            }
+
+            return this;
+        }
+    }
+
+    /**
+     * This method is called from within the constructor to initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is always
+     * regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+        java.awt.GridBagConstraints gridBagConstraints;
+
+        javax.swing.JTextPane descriptionField = new javax.swing.JTextPane();
+        javax.swing.JLabel ruleSetListLabel = new javax.swing.JLabel();
+        scrollPane = new javax.swing.JScrollPane();
+        javax.swing.JPanel buttonPanel = new javax.swing.JPanel();
+        newButton = new javax.swing.JButton();
+        deleteButton = new javax.swing.JButton();
+
+        setLayout(new java.awt.GridBagLayout());
+
+        descriptionField.setEditable(false);
+        descriptionField.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0)));
+        descriptionField.setText(org.openide.util.NbBundle.getMessage(RuleSetPanel.class, "RuleSetPanel.descriptionField.text")); // NOI18N
+        descriptionField.setOpaque(false);
+        gridBagConstraints = new java.awt.GridBagConstraints();
+        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
+        gridBagConstraints.weightx = 1.0;
+        add(descriptionField, gridBagConstraints);
+
+        org.openide.awt.Mnemonics.setLocalizedText(ruleSetListLabel, org.openide.util.NbBundle.getMessage(RuleSetPanel.class, "RuleSetPanel.ruleSetListLabel.text")); // NOI18N
+        gridBagConstraints = new java.awt.GridBagConstraints();
+        gridBagConstraints.gridx = 0;
+        gridBagConstraints.gridy = 1;
+        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
+        gridBagConstraints.insets = new java.awt.Insets(15, 0, 0, 0);
+        add(ruleSetListLabel, gridBagConstraints);
+        gridBagConstraints = new java.awt.GridBagConstraints();
+        gridBagConstraints.gridx = 0;
+        gridBagConstraints.gridy = 2;
+        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
+        gridBagConstraints.weightx = 1.0;
+        gridBagConstraints.weighty = 1.0;
+        gridBagConstraints.insets = new java.awt.Insets(5, 0, 10, 0);
+        add(scrollPane, gridBagConstraints);
+
+        buttonPanel.setLayout(new java.awt.GridLayout(1, 0, 5, 0));
+
+        newButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/add16.png"))); // NOI18N
+        org.openide.awt.Mnemonics.setLocalizedText(newButton, org.openide.util.NbBundle.getMessage(RuleSetPanel.class, "RuleSetPanel.newButton.text")); // NOI18N
+        buttonPanel.add(newButton);
+
+        deleteButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/delete16.png"))); // NOI18N
+        org.openide.awt.Mnemonics.setLocalizedText(deleteButton, org.openide.util.NbBundle.getMessage(RuleSetPanel.class, "RuleSetPanel.deleteButton.text")); // NOI18N
+        buttonPanel.add(deleteButton);
+
+        gridBagConstraints = new java.awt.GridBagConstraints();
+        gridBagConstraints.gridx = 0;
+        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
+        add(buttonPanel, gridBagConstraints);
+    }// </editor-fold>//GEN-END:initComponents
+
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JButton deleteButton;
+    private javax.swing.JButton newButton;
+    private javax.swing.JScrollPane scrollPane;
+    // End of variables declaration//GEN-END:variables
+}
diff --git a/Core/src/org/sleuthkit/autopsy/modules/yara/ui/YaraRuleSetOptionPanel.form b/Core/src/org/sleuthkit/autopsy/modules/yara/ui/YaraRuleSetOptionPanel.form
new file mode 100755
index 0000000000000000000000000000000000000000..680d63ebfcbcbf7d719ddb920b1e2ea23726bb1a
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/modules/yara/ui/YaraRuleSetOptionPanel.form
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<Form version="1.3" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
+  <Properties>
+    <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
+      <Border info="org.netbeans.modules.form.compat2.border.LineBorderInfo">
+        <LineBorder/>
+      </Border>
+    </Property>
+  </Properties>
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+    <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,2,45"/>
+  </AuxValues>
+
+  <Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
+  <SubComponents>
+    <Container class="javax.swing.JScrollPane" name="scrollPane">
+      <Properties>
+        <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
+          <Border info="null"/>
+        </Property>
+      </Properties>
+      <AuxValues>
+        <AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
+        <AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
+      </AuxValues>
+      <Constraints>
+        <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
+          <BorderConstraints direction="Center"/>
+        </Constraint>
+      </Constraints>
+
+      <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+      <SubComponents>
+        <Container class="javax.swing.JPanel" name="viewportPanel">
+          <AuxValues>
+            <AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
+            <AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
+          </AuxValues>
+
+          <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
+          <SubComponents>
+            <Component class="javax.swing.JSeparator" name="separator">
+              <Properties>
+                <Property name="orientation" type="int" value="1"/>
+              </Properties>
+              <AuxValues>
+                <AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
+                <AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
+              </AuxValues>
+              <Constraints>
+                <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
+                  <GridBagConstraints gridX="1" gridY="-1" gridWidth="1" gridHeight="1" fill="3" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="1.0"/>
+                </Constraint>
+              </Constraints>
+            </Component>
+            <Component class="org.sleuthkit.autopsy.modules.yara.ui.RuleSetDetailsPanel" name="ruleSetDetailsPanel">
+              <Properties>
+                <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                  <Dimension value="[500, 97]"/>
+                </Property>
+                <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                  <Dimension value="[500, 204]"/>
+                </Property>
+              </Properties>
+              <Constraints>
+                <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
+                  <GridBagConstraints gridX="2" gridY="-1" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="10" insetsLeft="10" insetsBottom="10" insetsRight="10" anchor="17" weightX="1.0" weightY="1.0"/>
+                </Constraint>
+              </Constraints>
+            </Component>
+            <Component class="org.sleuthkit.autopsy.modules.yara.ui.RuleSetPanel" name="ruleSetPanel">
+              <Properties>
+                <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                  <Dimension value="[400, 2147483647]"/>
+                </Property>
+                <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                  <Dimension value="[400, 107]"/>
+                </Property>
+                <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                  <Dimension value="[400, 214]"/>
+                </Property>
+              </Properties>
+              <Constraints>
+                <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
+                  <GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="3" ipadX="0" ipadY="0" insetsTop="10" insetsLeft="10" insetsBottom="10" insetsRight="10" anchor="17" weightX="0.0" weightY="1.0"/>
+                </Constraint>
+              </Constraints>
+            </Component>
+          </SubComponents>
+        </Container>
+      </SubComponents>
+    </Container>
+  </SubComponents>
+</Form>
diff --git a/Core/src/org/sleuthkit/autopsy/modules/yara/ui/YaraRuleSetOptionPanel.java b/Core/src/org/sleuthkit/autopsy/modules/yara/ui/YaraRuleSetOptionPanel.java
new file mode 100755
index 0000000000000000000000000000000000000000..18f32aaf69ec08f9be52050a97ba39784d127dbc
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/modules/yara/ui/YaraRuleSetOptionPanel.java
@@ -0,0 +1,186 @@
+/*
+ * Autopsy Forensic Browser
+ *
+ * Copyright 2020 Basis Technology Corp.
+ * Contact: carrier <at> sleuthkit <dot> org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.sleuthkit.autopsy.modules.yara.ui;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.swing.JOptionPane;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import org.openide.util.NbBundle;
+import org.sleuthkit.autopsy.modules.yara.rules.RuleSetException;
+import org.sleuthkit.autopsy.modules.yara.rules.RuleSetManager;
+
+/**
+ *
+ * Yara Rule Set Option Panel.
+ */
+public class YaraRuleSetOptionPanel extends javax.swing.JPanel {
+
+    private static final long serialVersionUID = 1L;
+
+    private static final Logger logger = Logger.getLogger(YaraRuleSetOptionPanel.class.getName());
+
+    private final RuleSetManager manager;
+
+    /**
+     * Creates new form YaraRuleSetOptionPanel
+     */
+    public YaraRuleSetOptionPanel() {
+        initComponents();
+
+        manager = new RuleSetManager();
+
+        ruleSetPanel.addListSelectionListener(new ListSelectionListener() {
+            @Override
+            public void valueChanged(ListSelectionEvent e) {
+                handleSelectionChange();
+            }
+        });
+
+        ruleSetPanel.addDeleteRuleListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                handleDeleteRuleSet();
+            }
+        });
+
+        ruleSetPanel.addNewRuleListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                handleNewRuleSet();
+            }
+        });
+    }
+
+    /**
+     * Update the panel with the current rule set.
+     */
+    void updatePanel() {
+        ruleSetPanel.addSetList(manager.getRuleSetList());
+    }
+
+    /**
+     * Handle the change in rule set selection. Update the detail panel with the
+     * selected rule.
+     */
+    private void handleSelectionChange() {
+        ruleSetDetailsPanel.setRuleSet(ruleSetPanel.getSelectedRule());
+    }
+
+    @NbBundle.Messages({
+        "YaraRuleSetOptionPanel_new_rule_set_name_msg=Supply a new unique rule set name:",
+        "YaraRuleSetOptionPanel_new_rule_set_name_title=Rule Set Name",
+        "# {0} - rule set name",
+        "YaraRuleSetOptionPanel_badName_msg=Rule set name {0} already exists.\nRule set names must be unique.",
+        "YaraRuleSetOptionPanel_badName_title=Create Rule Set"
+    })
+    /**
+     * Handle the new rule set action. Prompt the user for a rule set name,
+     * create the new set and update the rule set list.
+     */
+    private void handleNewRuleSet() {
+        String value = JOptionPane.showInputDialog(this,
+                Bundle.YaraRuleSetOptionPanel_new_rule_set_name_msg(),
+                Bundle.YaraRuleSetOptionPanel_new_rule_set_name_title());
+        try {
+            ruleSetPanel.addRuleSet(manager.createRuleSet(value));
+        } catch (RuleSetException ex) {
+            JOptionPane.showMessageDialog(this,
+                    Bundle.YaraRuleSetOptionPanel_badName_msg(value),
+                    Bundle.YaraRuleSetOptionPanel_badName_title(),
+                    JOptionPane.ERROR_MESSAGE);
+            logger.log(Level.WARNING, "Failed to create new rule set, user provide existing name.", ex);
+        }
+    }
+
+    /**
+     * Handle the delete rule action. Delete the rule set and update the the
+     * rule set list.
+     */
+    private void handleDeleteRuleSet() {
+        ruleSetPanel.removeRuleSet(ruleSetPanel.getSelectedRule());
+    }
+
+    /**
+     * This method is called from within the constructor to initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is always
+     * regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+        java.awt.GridBagConstraints gridBagConstraints;
+
+        javax.swing.JScrollPane scrollPane = new javax.swing.JScrollPane();
+        javax.swing.JPanel viewportPanel = new javax.swing.JPanel();
+        javax.swing.JSeparator separator = new javax.swing.JSeparator();
+        ruleSetDetailsPanel = new org.sleuthkit.autopsy.modules.yara.ui.RuleSetDetailsPanel();
+        ruleSetPanel = new org.sleuthkit.autopsy.modules.yara.ui.RuleSetPanel();
+
+        setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0)));
+        setLayout(new java.awt.BorderLayout());
+
+        scrollPane.setBorder(null);
+
+        viewportPanel.setLayout(new java.awt.GridBagLayout());
+
+        separator.setOrientation(javax.swing.SwingConstants.VERTICAL);
+        gridBagConstraints = new java.awt.GridBagConstraints();
+        gridBagConstraints.gridx = 1;
+        gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL;
+        gridBagConstraints.weighty = 1.0;
+        viewportPanel.add(separator, gridBagConstraints);
+
+        ruleSetDetailsPanel.setMinimumSize(new java.awt.Dimension(500, 97));
+        ruleSetDetailsPanel.setPreferredSize(new java.awt.Dimension(500, 204));
+        gridBagConstraints = new java.awt.GridBagConstraints();
+        gridBagConstraints.gridx = 2;
+        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
+        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
+        gridBagConstraints.weightx = 1.0;
+        gridBagConstraints.weighty = 1.0;
+        gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10);
+        viewportPanel.add(ruleSetDetailsPanel, gridBagConstraints);
+
+        ruleSetPanel.setMaximumSize(new java.awt.Dimension(400, 2147483647));
+        ruleSetPanel.setMinimumSize(new java.awt.Dimension(400, 107));
+        ruleSetPanel.setPreferredSize(new java.awt.Dimension(400, 214));
+        gridBagConstraints = new java.awt.GridBagConstraints();
+        gridBagConstraints.gridx = 0;
+        gridBagConstraints.gridy = 0;
+        gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL;
+        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
+        gridBagConstraints.weighty = 1.0;
+        gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10);
+        viewportPanel.add(ruleSetPanel, gridBagConstraints);
+
+        scrollPane.setViewportView(viewportPanel);
+
+        add(scrollPane, java.awt.BorderLayout.CENTER);
+    }// </editor-fold>//GEN-END:initComponents
+
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private org.sleuthkit.autopsy.modules.yara.ui.RuleSetDetailsPanel ruleSetDetailsPanel;
+    private org.sleuthkit.autopsy.modules.yara.ui.RuleSetPanel ruleSetPanel;
+    // End of variables declaration//GEN-END:variables
+}
diff --git a/Core/src/org/sleuthkit/autopsy/modules/yara/ui/YaraRuleSetsOptionPanelController.java b/Core/src/org/sleuthkit/autopsy/modules/yara/ui/YaraRuleSetsOptionPanelController.java
new file mode 100755
index 0000000000000000000000000000000000000000..7619e23b4ccec95907b388ed93a13e452e7b2100
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/modules/yara/ui/YaraRuleSetsOptionPanelController.java
@@ -0,0 +1,90 @@
+/*
+ * Autopsy Forensic Browser
+ *
+ * Copyright 2020 Basis Technology Corp.
+ * Contact: carrier <at> sleuthkit <dot> org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.sleuthkit.autopsy.modules.yara.ui;
+
+import java.beans.PropertyChangeListener;
+import javax.swing.JComponent;
+import org.netbeans.spi.options.OptionsPanelController;
+import org.openide.util.HelpCtx;
+import org.openide.util.Lookup;
+
+/**
+ * Yara rule set option panel controller.
+ *
+ */
+@OptionsPanelController.TopLevelRegistration(
+        categoryName = "#OptionCategory_Name_YaraRuleSetOption",
+        iconBase = "org/sleuthkit/autopsy/images/yara_32.png",
+        keywords = "#OptionCategory_Keywords_YaraRuleSetOption",
+        keywordsCategory = "YaraRuleSets",
+        position = 20
+)
+public class YaraRuleSetsOptionPanelController extends OptionsPanelController {
+
+    private YaraRuleSetOptionPanel panel = null;
+
+    @Override
+    public void update() {
+        if (panel != null) {
+            panel.updatePanel();
+        }
+    }
+
+    @Override
+    public void applyChanges() {
+
+    }
+
+    @Override
+    public void cancel() {
+
+    }
+
+    @Override
+    public JComponent getComponent(Lookup masterLookup) {
+        panel = new YaraRuleSetOptionPanel();
+        return panel;
+    }
+
+    @Override
+    public HelpCtx getHelpCtx() {
+        return null;
+    }
+
+    @Override
+    public void addPropertyChangeListener(PropertyChangeListener pl) {
+
+    }
+
+    @Override
+    public void removePropertyChangeListener(PropertyChangeListener pl) {
+
+    }
+
+    @Override
+    public boolean isValid() {
+        return true;
+    }
+
+    @Override
+    public boolean isChanged() {
+        return false;
+    }
+
+}