diff --git a/.env.test b/.env.test
new file mode 100644
index 0000000..d440e73
--- /dev/null
+++ b/.env.test
@@ -0,0 +1,5 @@
+ANTHROPIC_API_KEY=test-anthropic-key
+FORCE_REGENERATE=false
+CLI_ENV=cli
+NODE_ENV=test
+LOG_LEVEL=error
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 7f13a33..defb0e9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,10 +5,14 @@
 dist/
 node_modules/
 archive/
+coverage/
 
 # Ignore local database
 *.sqlite
 
+# Ignore aider files
+.aider*
+
 # Ignore macOS files
 .DS_Store
 
diff --git a/README.md b/README.md
index a0d7918..6f4378d 100644
--- a/README.md
+++ b/README.md
@@ -6,25 +6,8 @@ Welcome to the **Prompt Library**, a collection of categorized AI prompts for ea
 
 ## 📚 Table of Contents
 
-<!-- START doctoc generated TOC please keep comment here to allow auto update -->
-<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
-
-- [🎯 Purpose & Features](#-purpose--features)
-- [⚡ Quick Start](#-quick-start)
-- [🛠️ How It Works](#-how-it-works)
-- [🖥️ CLI Usage](#-cli-usage)
-  - [Interactive Menu](#interactive-menu)
-  - [List Prompts and Categories](#list-prompts-and-categories)
-  - [Sync Personal Library](#sync-personal-library)
-  - [Execute Prompts](#execute-prompts)
-- [📂 Prompt Library Example](#-prompt-library-example)
-- [🚀 Getting Started](#-getting-started)
-- [🧩 Using Fragments](#-using-fragments)
-- [⚙️ Metadata Customization](#-metadata-customization)
-- [🤝 Contributing](#-contributing)
-- [📄 License](#-license)
-
-<!-- END doctoc generated TOC please keep comment here to allow auto update -->
+<!-- START doctoc -->
+<!-- END doctoc -->
 
 ## 🎯 Purpose & Features
 
@@ -128,9 +111,9 @@ prompt-library-cli execute --help
 - [Git Branch Name Generator](prompts/git_branch_name_generator/README.md) - Generates optimized git branch names based on project context and user requirements
 - [Git Commit Message Agent](prompts/git_commit_message_agent/README.md) - Generates precise and informative git commit messages following Conventional Commits specification
 - [GitHub Issue Creator](prompts/github_issue_creator_agent/README.md) - Creates comprehensive and actionable GitHub issues based on provided project information
-- [Software Architect Visionary](prompts/software_architect_agent/README.md) - Analyzes user requirements and creates comprehensive software specification documents
 - [Software Architect Code Reviewer](prompts/software_architect_code_reviewer/README.md) - Generates comprehensive pull requests with architectural analysis and optimization suggestions
 - [Software Architect Specification Creator](prompts/software_architect_spec_creator/README.md) - Creates comprehensive software specification documents based on user requirements
+- [Software Architect Visionary](prompts/software_architect_agent/README.md) - Analyzes user requirements and creates comprehensive software specification documents
 - [Software Development Expert Agent](prompts/software_dev_expert_agent/README.md) - Provides expert, adaptive assistance across all aspects of the software development lifecycle.
 
 </details>
@@ -143,8 +126,8 @@ prompt-library-cli execute --help
 <details>
 <summary><strong>Healthcare</strong></summary>
 
-- [Psychological Support and Therapy Agent](prompts/psychological_support_agent/README.md) - Provides AI-driven psychological support and therapy through digital platforms
 - [Health Optimization Agent](prompts/health_optimization_agent/README.md) - Generates personalized, adaptive health optimization plans based on comprehensive user data analysis
+- [Psychological Support and Therapy Agent](prompts/psychological_support_agent/README.md) - Provides AI-driven psychological support and therapy through digital platforms
 
 </details>
 <details>
diff --git a/jest.config.js b/jest.config.js
index c924a13..2044cd6 100644
--- a/jest.config.js
+++ b/jest.config.js
@@ -1,10 +1,21 @@
 module.exports = {
     preset: 'ts-jest',
     testEnvironment: 'node',
-    testMatch: ['**/tests/**/*.test.ts'],
-    globals: {
-        'ts-jest': {
+    setupFiles: ['<rootDir>/jest.setup.ts'],
+    testMatch: ['<rootDir>/src/**/__tests__/**/*.test.ts'],
+    moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
+    moduleNameMapper: {
+        '^@/(.*)$': '<rootDir>/src/$1'
+    },
+    transform: {
+        '^.+\\.ts?$': ['ts-jest', {
             tsconfig: 'tsconfig.test.json'
-        }
-    }
-};
+        }]
+    },
+    collectCoverage: true,
+    coverageDirectory: 'coverage',
+    coveragePathIgnorePatterns: [
+        '/node_modules/',
+        '/dist/'
+    ]
+};
\ No newline at end of file
diff --git a/jest.setup.ts b/jest.setup.ts
new file mode 100644
index 0000000..2a7040e
--- /dev/null
+++ b/jest.setup.ts
@@ -0,0 +1,10 @@
+import * as path from 'path';
+import dotenv from 'dotenv';
+
+const originalEnv = { ...process.env };
+const envTestPath = path.resolve(__dirname, '.env.test');
+dotenv.config({ path: envTestPath });
+
+process.env.NODE_ENV = 'test';
+
+export { originalEnv };
diff --git a/package-lock.json b/package-lock.json
index e5191c8..cd5f755 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12,7 +12,7 @@
                 "@anthropic-ai/sdk": "0.29.1",
                 "@inquirer/prompts": "7.0.0",
                 "chalk": "4.1.2",
-                "cli-spinner": "^0.2.10",
+                "cli-spinner": "0.2.10",
                 "commander": "12.1.0",
                 "dotenv": "16.4.5",
                 "fs-extra": "11.2.0",
@@ -26,9 +26,11 @@
             },
             "devDependencies": {
                 "@eslint/compat": "1.2.0",
+                "@jest/globals": "29.7.0",
+                "@testing-library/jest-dom": "6.4.2",
                 "@types/fs-extra": "11.0.4",
                 "@types/inquirer": "9.0.7",
-                "@types/jest": "29.5.13",
+                "@types/jest": "29.5.14",
                 "@types/js-yaml": "4.0.9",
                 "@types/node": "22.7.6",
                 "@types/node-cache": "4.2.5",
@@ -44,6 +46,8 @@
                 "eslint-plugin-simple-import-sort": "12.1.1",
                 "eslint-plugin-unused-imports": "4.1.4",
                 "jest": "29.7.0",
+                "jest-environment-node": "29.7.0",
+                "mock-fs": "5.2.0",
                 "npm-check-updates": "17.1.4",
                 "prettier": "3.3.3",
                 "ts-jest": "29.2.5",
@@ -52,6 +56,13 @@
                 "yaml-lint": "1.7.0"
             }
         },
+        "node_modules/@adobe/css-tools": {
+            "version": "4.4.0",
+            "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.0.tgz",
+            "integrity": "sha512-Ff9+ksdQQB3rMncgqDK78uLznstjyfIf2Arnh22pW8kBpLs6rpKDwgnZT46hin5Hl1WzazzK64DOrhSwYpS7bQ==",
+            "dev": true,
+            "license": "MIT"
+        },
         "node_modules/@ampproject/remapping": {
             "version": "2.3.0",
             "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
@@ -654,6 +665,19 @@
                 "@babel/core": "^7.0.0-0"
             }
         },
+        "node_modules/@babel/runtime": {
+            "version": "7.25.9",
+            "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.9.tgz",
+            "integrity": "sha512-4zpTHZ9Cm6L9L+uIqghQX8ZXg8HKFcjYO3qHoO8zTmRm6HQUJ8SSJ+KRvbMBZn0EGVlT4DRYeQ/6hjlyXBh+Kg==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "regenerator-runtime": "^0.14.0"
+            },
+            "engines": {
+                "node": ">=6.9.0"
+            }
+        },
         "node_modules/@babel/template": {
             "version": "7.25.7",
             "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.7.tgz",
@@ -1747,6 +1771,66 @@
                 "@sinonjs/commons": "^3.0.0"
             }
         },
+        "node_modules/@testing-library/jest-dom": {
+            "version": "6.4.2",
+            "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.4.2.tgz",
+            "integrity": "sha512-CzqH0AFymEMG48CpzXFriYYkOjk6ZGPCLMhW9e9jg3KMCn5OfJecF8GtGW7yGfR/IgCe3SX8BSwjdzI6BBbZLw==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "@adobe/css-tools": "^4.3.2",
+                "@babel/runtime": "^7.9.2",
+                "aria-query": "^5.0.0",
+                "chalk": "^3.0.0",
+                "css.escape": "^1.5.1",
+                "dom-accessibility-api": "^0.6.3",
+                "lodash": "^4.17.15",
+                "redent": "^3.0.0"
+            },
+            "engines": {
+                "node": ">=14",
+                "npm": ">=6",
+                "yarn": ">=1"
+            },
+            "peerDependencies": {
+                "@jest/globals": ">= 28",
+                "@types/bun": "latest",
+                "@types/jest": ">= 28",
+                "jest": ">= 28",
+                "vitest": ">= 0.32"
+            },
+            "peerDependenciesMeta": {
+                "@jest/globals": {
+                    "optional": true
+                },
+                "@types/bun": {
+                    "optional": true
+                },
+                "@types/jest": {
+                    "optional": true
+                },
+                "jest": {
+                    "optional": true
+                },
+                "vitest": {
+                    "optional": true
+                }
+            }
+        },
+        "node_modules/@testing-library/jest-dom/node_modules/chalk": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
+            "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "ansi-styles": "^4.1.0",
+                "supports-color": "^7.1.0"
+            },
+            "engines": {
+                "node": ">=8"
+            }
+        },
         "node_modules/@textlint/ast-node-types": {
             "version": "12.6.1",
             "resolved": "https://registry.npmjs.org/@textlint/ast-node-types/-/ast-node-types-12.6.1.tgz",
@@ -1922,9 +2006,9 @@
             }
         },
         "node_modules/@types/jest": {
-            "version": "29.5.13",
-            "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.13.tgz",
-            "integrity": "sha512-wd+MVEZCHt23V0/L642O5APvspWply/rGY5BcW4SUETo2UzPU3Z26qr8jC2qxpimI2jjx9h7+2cj2FwIr01bXg==",
+            "version": "29.5.14",
+            "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.14.tgz",
+            "integrity": "sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==",
             "dev": true,
             "license": "MIT",
             "dependencies": {
@@ -2496,6 +2580,16 @@
             "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
             "license": "Python-2.0"
         },
+        "node_modules/aria-query": {
+            "version": "5.3.2",
+            "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz",
+            "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==",
+            "dev": true,
+            "license": "Apache-2.0",
+            "engines": {
+                "node": ">= 0.4"
+            }
+        },
         "node_modules/array-buffer-byte-length": {
             "version": "1.0.1",
             "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz",
@@ -3367,6 +3461,13 @@
                 "node": ">= 8"
             }
         },
+        "node_modules/css.escape": {
+            "version": "1.5.1",
+            "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz",
+            "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==",
+            "dev": true,
+            "license": "MIT"
+        },
         "node_modules/data-view-buffer": {
             "version": "1.0.1",
             "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz",
@@ -3616,6 +3717,13 @@
                 "doctoc": "doctoc.js"
             }
         },
+        "node_modules/dom-accessibility-api": {
+            "version": "0.6.3",
+            "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz",
+            "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==",
+            "dev": true,
+            "license": "MIT"
+        },
         "node_modules/dom-serializer": {
             "version": "1.4.1",
             "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz",
@@ -5289,8 +5397,8 @@
             "version": "4.0.0",
             "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
             "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
+            "devOptional": true,
             "license": "MIT",
-            "optional": true,
             "engines": {
                 "node": ">=8"
             }
@@ -6580,6 +6688,13 @@
                 "url": "https://github.com/sponsors/sindresorhus"
             }
         },
+        "node_modules/lodash": {
+            "version": "4.17.21",
+            "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+            "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
+            "dev": true,
+            "license": "MIT"
+        },
         "node_modules/lodash.memoize": {
             "version": "4.1.2",
             "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
@@ -7089,6 +7204,16 @@
                 "url": "https://github.com/sponsors/sindresorhus"
             }
         },
+        "node_modules/min-indent": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
+            "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=4"
+            }
+        },
         "node_modules/minimatch": {
             "version": "3.1.2",
             "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@@ -7236,6 +7361,16 @@
             "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
             "license": "MIT"
         },
+        "node_modules/mock-fs": {
+            "version": "5.2.0",
+            "resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-5.2.0.tgz",
+            "integrity": "sha512-2dF2R6YMSZbpip1V1WHKGLNjr/k48uQClqMVb5H3MOvwc9qhYis3/IWbj02qIg/Y8MDXKFF4c5v0rxx2o6xTZw==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=12.0.0"
+            }
+        },
         "node_modules/ms": {
             "version": "2.1.3",
             "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
@@ -8229,6 +8364,27 @@
                 "node": ">= 6"
             }
         },
+        "node_modules/redent": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz",
+            "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "indent-string": "^4.0.0",
+                "strip-indent": "^3.0.0"
+            },
+            "engines": {
+                "node": ">=8"
+            }
+        },
+        "node_modules/regenerator-runtime": {
+            "version": "0.14.1",
+            "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
+            "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
+            "dev": true,
+            "license": "MIT"
+        },
         "node_modules/regexp.prototype.flags": {
             "version": "1.5.3",
             "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.3.tgz",
@@ -8959,6 +9115,19 @@
                 "node": ">=6"
             }
         },
+        "node_modules/strip-indent": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz",
+            "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "min-indent": "^1.0.0"
+            },
+            "engines": {
+                "node": ">=8"
+            }
+        },
         "node_modules/strip-json-comments": {
             "version": "3.1.1",
             "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
diff --git a/package.json b/package.json
index e7e8b5a..558bc77 100644
--- a/package.json
+++ b/package.json
@@ -16,13 +16,14 @@
         "lint:fix": "npm run lint -- --fix",
         "prettify": "prettier --write 'src/**/*.ts'",
         "start": "node dist/cli/index.js",
-        "test": "jest --passWithNoTests",
+        "test": "jest",
         "test:watch": "jest --watch",
+        "test:coverage": "jest --coverage",
         "toc": "doctoc README.md --github --notitle",
         "type-check": "tsc --noEmit",
         "update": "ncu -i",
-        "update-metadata": "ts-node src/app/core/update_metadata.ts",
-        "update-views": "ts-node src/app/core/update_views.ts",
+        "update-metadata": "ts-node src/app/controllers/update-metadata.ts",
+        "update-views": "ts-node src/app/controllers/update-views.ts",
         "validate-yaml": "yamllint '**/*.yml'"
     },
     "keywords": [
@@ -45,7 +46,7 @@
         "@anthropic-ai/sdk": "0.29.1",
         "@inquirer/prompts": "7.0.0",
         "chalk": "4.1.2",
-        "cli-spinner": "^0.2.10",
+        "cli-spinner": "0.2.10",
         "commander": "12.1.0",
         "dotenv": "16.4.5",
         "fs-extra": "11.2.0",
@@ -56,9 +57,11 @@
     },
     "devDependencies": {
         "@eslint/compat": "1.2.0",
+        "@jest/globals": "29.7.0",
+        "@testing-library/jest-dom": "6.4.2",
         "@types/fs-extra": "11.0.4",
         "@types/inquirer": "9.0.7",
-        "@types/jest": "29.5.13",
+        "@types/jest": "29.5.14",
         "@types/js-yaml": "4.0.9",
         "@types/node": "22.7.6",
         "@types/node-cache": "4.2.5",
@@ -74,6 +77,8 @@
         "eslint-plugin-simple-import-sort": "12.1.1",
         "eslint-plugin-unused-imports": "4.1.4",
         "jest": "29.7.0",
+        "jest-environment-node": "29.7.0",
+        "mock-fs": "5.2.0",
         "npm-check-updates": "17.1.4",
         "prettier": "3.3.3",
         "ts-jest": "29.2.5",
diff --git a/prompts/software_architect_code_reviewer/README.md b/prompts/software_architect_code_reviewer/README.md
index 14d159e..2a6fbc1 100644
--- a/prompts/software_architect_code_reviewer/README.md
+++ b/prompts/software_architect_code_reviewer/README.md
@@ -19,7 +19,6 @@ This prompt simulates a world-class software architect and code reviewer, tasked
 ### 🧩 Relevant Fragments
 
 This prompt could potentially use the following fragments:
-- [Prompt Engineering Guidelines Max](/fragments/prompt_engineering/prompt_engineering_guidelines_max.md) - Could be used into `{{EXTRA_GUIDELINES_OR_CONTEXT}}`
 - [Safety Guidelines](/fragments/prompt_engineering/safety_guidelines.md) - Could be used into `{{SAFETY_GUIDELINES}}`
 - [Behavior Attributes](/fragments/prompt_engineering/behavior_attributes.md) - Could be used into `{{AI_BEHAVIOR_ATTRIBUTES}}`
 
diff --git a/prompts/software_architect_code_reviewer/metadata.yml b/prompts/software_architect_code_reviewer/metadata.yml
index f33113b..960d243 100644
--- a/prompts/software_architect_code_reviewer/metadata.yml
+++ b/prompts/software_architect_code_reviewer/metadata.yml
@@ -6,9 +6,6 @@ description: >-
   innovative improvements to elevate entire codebases.
 directory: software_architect_code_reviewer
 fragments:
-  - category: prompt_engineering
-    name: prompt_engineering_guidelines_max
-    variable: '{{EXTRA_GUIDELINES_OR_CONTEXT}}'
   - category: prompt_engineering
     name: safety_guidelines
     variable: '{{SAFETY_GUIDELINES}}'
diff --git a/src/app/config/app.config.ts b/src/app/config/app-config.ts
similarity index 81%
rename from src/app/config/app.config.ts
rename to src/app/config/app-config.ts
index 9e99b10..21e0a2b 100644
--- a/src/app/config/app.config.ts
+++ b/src/app/config/app-config.ts
@@ -10,7 +10,7 @@ export interface AppConfig {
     VIEW_TEMPLATE_NAME: string;
     README_TEMPLATE_NAME: string;
     DEFAULT_CATEGORY: string;
-    FORCE_REGENERATE: string;
+    FORCE_REGENERATE: boolean;
     YAML_INDENT: number;
     YAML_LINE_WIDTH: number;
 }
@@ -22,10 +22,10 @@ export const appConfig: AppConfig = {
     ANALYZER_PROMPT_PATH: path.join('src', 'system_prompts', 'prompt_analysis_agent', 'prompt.md'),
     README_PATH: 'README.md',
     VIEW_FILE_NAME: 'README.md',
-    VIEW_TEMPLATE_NAME: 'sub_readme.md',
-    README_TEMPLATE_NAME: 'main_readme.md',
+    VIEW_TEMPLATE_NAME: 'sub-readme.md',
+    README_TEMPLATE_NAME: 'main-readme.md',
     DEFAULT_CATEGORY: 'uncategorized',
-    FORCE_REGENERATE: process.env.FORCE_REGENERATE ?? 'false',
+    FORCE_REGENERATE: process.env.FORCE_REGENERATE === 'true',
     YAML_INDENT: 2,
     YAML_LINE_WIDTH: 80
 };
diff --git a/src/app/controllers/__tests__/update-metadata.test.ts b/src/app/controllers/__tests__/update-metadata.test.ts
new file mode 100644
index 0000000..9a15127
--- /dev/null
+++ b/src/app/controllers/__tests__/update-metadata.test.ts
@@ -0,0 +1,272 @@
+import * as crypto from 'crypto';
+import * as path from 'path';
+
+import { jest } from '@jest/globals';
+
+import { commonConfig } from '../../../shared/config/common-config';
+import { PromptMetadata } from '../../../shared/types';
+import * as fileSystem from '../../../shared/utils/file-system';
+import logger from '../../../shared/utils/logger';
+import { appConfig } from '../../config/app-config';
+import * as promptAnalyzer from '../../utils/metadata-generator';
+import { generateMetadata, shouldUpdateMetadata, updateMetadataHash, updatePromptMetadata } from '../update-metadata';
+
+jest.mock('../../../shared/utils/file-system');
+jest.mock('../../utils/metadata-generator');
+jest.mock('../../../shared/utils/logger');
+jest.mock('fs-extra');
+
+describe('UpdateMetadataController', () => {
+    const mockPromptContent = 'Test prompt content';
+    const mockMetadata: PromptMetadata = {
+        title: 'Test Prompt',
+        primary_category: 'Testing',
+        directory: 'test-prompt',
+        one_line_description: 'A test prompt',
+        description: 'Test description',
+        subcategories: ['unit-test'],
+        tags: ['test'],
+        variables: []
+    };
+    beforeEach(() => {
+        jest.clearAllMocks();
+        jest.mocked(promptAnalyzer.processMetadataGeneration).mockResolvedValue(mockMetadata);
+        jest.mocked(fileSystem.readFileContent).mockResolvedValue(mockPromptContent);
+        jest.mocked(fileSystem.fileExists).mockResolvedValue(true);
+        jest.mocked(fileSystem.writeFileContent).mockResolvedValue();
+        jest.mocked(fileSystem.createDirectory).mockResolvedValue();
+        jest.mocked(fileSystem.isDirectory).mockResolvedValue(true);
+        jest.mocked(fileSystem.readDirectory).mockResolvedValue(['test-prompt']);
+        jest.mocked(fileSystem.renameFile).mockResolvedValue();
+        jest.mocked(fileSystem.removeDirectory).mockResolvedValue();
+        jest.mocked(fileSystem.isFile).mockResolvedValue(true);
+        jest.mocked(fileSystem.copyFile).mockResolvedValue();
+    });
+
+    describe('generateMetadata', () => {
+        it('should generate metadata from prompt content', async () => {
+            const result = await generateMetadata(mockPromptContent);
+            expect(result).toEqual(mockMetadata);
+            expect(promptAnalyzer.processMetadataGeneration).toHaveBeenCalledWith(mockPromptContent);
+        });
+
+        it('should handle errors during metadata generation', async () => {
+            const error = new Error('Generation failed');
+            jest.mocked(promptAnalyzer.processMetadataGeneration).mockRejectedValue(error);
+
+            await expect(generateMetadata(mockPromptContent)).rejects.toThrow(error);
+            expect(logger.error).toHaveBeenCalled();
+        });
+    });
+
+    describe('shouldUpdateMetadata', () => {
+        const promptFile = 'test.md';
+        const metadataFile = 'metadata.yml';
+        beforeEach(() => {
+            jest.mocked(fileSystem.readFileContent).mockResolvedValue(mockPromptContent);
+            jest.mocked(fileSystem.fileExists).mockResolvedValue(true);
+            appConfig.FORCE_REGENERATE = false;
+        });
+
+        it('should return true when force regenerate is enabled', async () => {
+            appConfig.FORCE_REGENERATE = true;
+            const [shouldUpdate, _promptHash] = await shouldUpdateMetadata(promptFile, metadataFile);
+            expect(shouldUpdate).toBe(true);
+        });
+
+        it('should return true when metadata file does not exist', async () => {
+            jest.mocked(fileSystem.fileExists).mockResolvedValue(false);
+            const [shouldUpdate, _promptHash] = await shouldUpdateMetadata(promptFile, metadataFile);
+            expect(shouldUpdate).toBe(true);
+        });
+
+        it('should return true when content hash is missing', async () => {
+            jest.mocked(fileSystem.readFileContent).mockResolvedValue('no hash here');
+            const [shouldUpdate, _promptHash] = await shouldUpdateMetadata(promptFile, metadataFile);
+            expect(shouldUpdate).toBe(true);
+        });
+
+        it('should return true when content hash differs', async () => {
+            const promptContent = 'prompt content';
+            const differentHash = 'different-hash-value';
+            jest.mocked(fileSystem.readFileContent)
+                .mockResolvedValueOnce(promptContent)
+                .mockResolvedValueOnce(`content_hash: ${differentHash}`);
+
+            const [shouldUpdate] = await shouldUpdateMetadata(promptFile, metadataFile);
+            expect(shouldUpdate).toBe(true);
+        });
+
+        it('should return false when content hash matches', async () => {
+            appConfig.FORCE_REGENERATE = false;
+
+            const promptContent = 'test content';
+            const computedHash = crypto.createHash('md5').update(promptContent).digest('hex');
+            const mockMetadataContent = `content_hash: ${computedHash}`;
+            jest.mocked(fileSystem.fileExists).mockResolvedValue(true);
+            jest.mocked(fileSystem.readFileContent)
+                .mockResolvedValueOnce(promptContent)
+                .mockResolvedValueOnce(mockMetadataContent);
+
+            const [shouldUpdate] = await shouldUpdateMetadata(promptFile, metadataFile);
+            expect(shouldUpdate).toBe(false);
+        });
+    });
+
+    describe('updateMetadataHash', () => {
+        const metadataFile = 'metadata.yml';
+        const newHash = 'newhash123';
+        it('should update existing hash in metadata file', async () => {
+            const mockMetadataContent = `content_hash: oldHash123`;
+            jest.mocked(fileSystem.readFileContent)
+                .mockResolvedValueOnce(mockPromptContent)
+                .mockResolvedValueOnce(mockMetadataContent);
+            await updateMetadataHash(metadataFile, newHash);
+
+            expect(fileSystem.writeFileContent).toHaveBeenCalledWith(
+                metadataFile,
+                expect.stringContaining(`content_hash: ${newHash}`)
+            );
+        });
+
+        it('should add hash if not present in metadata file', async () => {
+            const mockMetadataContent = `
+title: Test
+description: Test description
+other: content
+`;
+            jest.mocked(fileSystem.readFileContent).mockResolvedValue(mockMetadataContent);
+            await updateMetadataHash(metadataFile, newHash);
+
+            expect(fileSystem.writeFileContent).toHaveBeenCalledWith(
+                metadataFile,
+                expect.stringContaining(`content_hash: ${newHash}`)
+            );
+        });
+
+        it('should handle errors during hash update', async () => {
+            const error = new Error('Update failed');
+            jest.mocked(fileSystem.readFileContent).mockRejectedValue(error);
+            jest.mocked(fileSystem.writeFileContent).mockRejectedValue(error);
+
+            await expect(updateMetadataHash(metadataFile, newHash)).rejects.toThrow(error);
+            expect(logger.error).toHaveBeenCalled();
+        });
+    });
+
+    describe('updatePromptMetadata', () => {
+        it('should process main prompt file if it exists', async () => {
+            const mainPromptFile = path.join(appConfig.PROMPTS_DIR, commonConfig.PROMPT_FILE_NAME);
+            jest.mocked(fileSystem.fileExists).mockResolvedValueOnce(true);
+
+            await updatePromptMetadata();
+
+            expect(fileSystem.readFileContent).toHaveBeenCalledWith(mainPromptFile);
+            expect(fileSystem.createDirectory).toHaveBeenCalled();
+            expect(fileSystem.renameFile).toHaveBeenCalled();
+            expect(fileSystem.writeFileContent).toHaveBeenCalled();
+        });
+
+        it('should process prompt directories', async () => {
+            jest.mocked(fileSystem.fileExists).mockResolvedValueOnce(false).mockResolvedValueOnce(true);
+
+            await updatePromptMetadata();
+
+            expect(fileSystem.readDirectory).toHaveBeenCalledWith(appConfig.PROMPTS_DIR);
+            expect(fileSystem.isDirectory).toHaveBeenCalled();
+            expect(fileSystem.readFileContent).toHaveBeenCalled();
+        });
+
+        it('should handle errors during prompt processing', async () => {
+            const error = new Error('Processing failed');
+            jest.mocked(fileSystem.readDirectory).mockRejectedValue(error);
+
+            await expect(updatePromptMetadata()).rejects.toThrow('Processing failed');
+            expect(logger.error).toHaveBeenCalled();
+        });
+
+        it('should handle existing target directory during rename', async () => {
+            const oldDir = 'old-prompt';
+            const newDir = 'new-prompt';
+            const promptFile = commonConfig.PROMPT_FILE_NAME;
+            jest.mocked(fileSystem.fileExists).mockImplementation((filePath: string) => {
+                if (filePath.includes('prompt.md')) {
+                    return Promise.resolve(true);
+                } else if (filePath.includes('metadata.yml')) {
+                    return Promise.resolve(true);
+                } else if (filePath.includes(newDir)) {
+                    return Promise.resolve(true);
+                } else {
+                    return Promise.resolve(false);
+                }
+            });
+
+            jest.mocked(fileSystem.readDirectory).mockImplementation((dirPath: string) => {
+                if (dirPath === appConfig.PROMPTS_DIR) {
+                    return Promise.resolve([oldDir]);
+                } else if (dirPath.includes(oldDir)) {
+                    return Promise.resolve([promptFile]);
+                } else {
+                    return Promise.resolve([]);
+                }
+            });
+
+            jest.mocked(promptAnalyzer.processMetadataGeneration).mockResolvedValue({
+                ...mockMetadata,
+                directory: newDir
+            });
+
+            await updatePromptMetadata();
+
+            expect(fileSystem.copyFile).toHaveBeenCalledWith(
+                expect.stringContaining(path.join(oldDir, promptFile)),
+                expect.stringContaining(path.join(newDir, promptFile))
+            );
+
+            expect(fileSystem.removeDirectory).toHaveBeenCalledWith(expect.stringContaining(oldDir));
+        });
+
+        it('should handle existing target directory during rename', async () => {
+            const oldDir = 'old-prompt';
+            const newDir = 'new-prompt';
+            const promptFile = commonConfig.PROMPT_FILE_NAME;
+            jest.mocked(fileSystem.fileExists).mockImplementation((filePath: string) => {
+                if (filePath.includes('prompt.md')) {
+                    return Promise.resolve(true);
+                } else if (filePath.includes('metadata.yml')) {
+                    return Promise.resolve(true);
+                } else if (filePath.includes(newDir)) {
+                    return Promise.resolve(true);
+                } else {
+                    return Promise.resolve(false);
+                }
+            });
+
+            jest.mocked(fileSystem.readDirectory).mockImplementation((dirPath: string) => {
+                if (dirPath === appConfig.PROMPTS_DIR) {
+                    return Promise.resolve([oldDir]);
+                } else if (dirPath.includes(oldDir)) {
+                    return Promise.resolve([promptFile]);
+                } else {
+                    return Promise.resolve([]);
+                }
+            });
+
+            jest.mocked(promptAnalyzer.processMetadataGeneration).mockResolvedValue({
+                ...mockMetadata,
+                directory: newDir
+            });
+
+            jest.mocked(fileSystem.isFile).mockResolvedValue(true);
+            jest.mocked(fileSystem.isDirectory).mockResolvedValue(true);
+
+            await updatePromptMetadata();
+
+            expect(fileSystem.copyFile).toHaveBeenCalledWith(
+                expect.stringContaining(path.join(oldDir, promptFile)),
+                expect.stringContaining(path.join(newDir, promptFile))
+            );
+            expect(fileSystem.removeDirectory).toHaveBeenCalledWith(expect.stringContaining(oldDir));
+        });
+    });
+});
diff --git a/src/app/controllers/__tests__/update-views.test.ts b/src/app/controllers/__tests__/update-views.test.ts
new file mode 100644
index 0000000..2ad8e29
--- /dev/null
+++ b/src/app/controllers/__tests__/update-views.test.ts
@@ -0,0 +1,121 @@
+import * as path from 'path';
+
+import { jest } from '@jest/globals';
+import * as nunjucks from 'nunjucks';
+
+import { commonConfig } from '../../../shared/config/common-config';
+import { PromptMetadata } from '../../../shared/types';
+import * as fileSystem from '../../../shared/utils/file-system';
+import logger from '../../../shared/utils/logger';
+import { appConfig } from '../../config/app-config';
+import { updateViews } from '../update-views';
+
+jest.mock('nunjucks');
+jest.mock('../../../shared/utils/file-system');
+jest.mock('../../../shared/utils/logger');
+
+describe('UpdateViewsController', () => {
+    const mockPromptDir = 'test-prompt';
+    const mockPromptPath = path.join(appConfig.PROMPTS_DIR, mockPromptDir);
+    const mockMetadata: PromptMetadata = {
+        title: 'Test Prompt',
+        primary_category: 'Testing',
+        one_line_description: 'A test prompt',
+        subcategories: ['unit-test'],
+        description: '',
+        directory: '',
+        tags: [],
+        variables: []
+    };
+    const mockPromptContent = 'Test prompt content';
+    const mockViewContent = 'Generated view content';
+    beforeEach(() => {
+        jest.clearAllMocks();
+        jest.mocked(fileSystem.isDirectory).mockResolvedValue(true);
+        jest.mocked(fileSystem.readDirectory).mockResolvedValue([mockPromptDir]);
+        jest.mocked(fileSystem.readFileContent).mockImplementation(async (filePath: string) => {
+            if (filePath.endsWith(commonConfig.PROMPT_FILE_NAME)) {
+                return mockPromptContent;
+            }
+
+            if (filePath.endsWith(commonConfig.METADATA_FILE_NAME)) {
+                return JSON.stringify(mockMetadata);
+            }
+            return '';
+        });
+        jest.mocked(fileSystem.writeFileContent).mockResolvedValue();
+        jest.mocked(nunjucks.render).mockImplementation(() => mockViewContent);
+        jest.mocked(nunjucks.configure).mockReturnValue(new nunjucks.Environment());
+    });
+
+    it('should process prompt directories and generate views', async () => {
+        await updateViews();
+        expect(nunjucks.configure).toHaveBeenCalledWith(appConfig.TEMPLATES_DIR, { autoescape: false });
+        expect(fileSystem.readDirectory).toHaveBeenCalledWith(appConfig.PROMPTS_DIR);
+
+        expect(fileSystem.readFileContent).toHaveBeenCalledWith(
+            path.join(mockPromptPath, commonConfig.PROMPT_FILE_NAME)
+        );
+        expect(fileSystem.readFileContent).toHaveBeenCalledWith(
+            path.join(mockPromptPath, commonConfig.METADATA_FILE_NAME)
+        );
+        expect(nunjucks.render).toHaveBeenCalledWith(
+            appConfig.VIEW_TEMPLATE_NAME,
+            expect.objectContaining({
+                metadata: mockMetadata,
+                prompt_content: mockPromptContent
+            })
+        );
+        expect(fileSystem.writeFileContent).toHaveBeenCalledWith(
+            path.join(mockPromptPath, appConfig.VIEW_FILE_NAME),
+            mockViewContent
+        );
+        expect(nunjucks.render).toHaveBeenCalledWith(
+            appConfig.README_TEMPLATE_NAME,
+            expect.objectContaining({
+                categories: expect.any(Object)
+            })
+        );
+    });
+
+    it('should handle errors gracefully', async () => {
+        const mockError = new Error('Test error');
+        jest.mocked(fileSystem.readDirectory).mockRejectedValue(mockError);
+
+        await expect(updateViews()).rejects.toThrow(mockError);
+        expect(logger.error).toHaveBeenCalled();
+    });
+
+    it('should skip non-directory entries', async () => {
+        jest.mocked(fileSystem.isDirectory).mockResolvedValue(false);
+
+        await updateViews();
+
+        expect(fileSystem.readFileContent).not.toHaveBeenCalled();
+        expect(nunjucks.render).toHaveBeenCalledTimes(1);
+    });
+
+    it('should use default category when primary_category is missing', async () => {
+        const metadataWithoutCategory: PromptMetadata = {
+            ...mockMetadata,
+            primary_category: appConfig.DEFAULT_CATEGORY
+        };
+        jest.mocked(fileSystem.readFileContent).mockImplementation(async (filePath: string) => {
+            if (filePath.endsWith(commonConfig.METADATA_FILE_NAME)) {
+                return JSON.stringify(metadataWithoutCategory);
+            }
+            return mockPromptContent;
+        });
+
+        await updateViews();
+
+        expect(nunjucks.render).toHaveBeenCalledWith(
+            appConfig.README_TEMPLATE_NAME,
+            expect.objectContaining({
+                categories: expect.objectContaining({
+                    [appConfig.DEFAULT_CATEGORY]: expect.any(Array)
+                })
+            })
+        );
+    });
+});
diff --git a/src/app/core/update_metadata.ts b/src/app/controllers/update-metadata.ts
similarity index 88%
rename from src/app/core/update_metadata.ts
rename to src/app/controllers/update-metadata.ts
index e19dc3b..286b6b1 100644
--- a/src/app/core/update_metadata.ts
+++ b/src/app/controllers/update-metadata.ts
@@ -1,8 +1,8 @@
 import * as crypto from 'crypto';
 import * as path from 'path';
 
-import { commonConfig } from '../../shared/config/common.config';
-import { Metadata } from '../../shared/types';
+import { commonConfig } from '../../shared/config/common-config';
+import { PromptMetadata } from '../../shared/types';
 import {
     copyFile,
     createDirectory,
@@ -14,13 +14,13 @@ import {
     removeDirectory,
     renameFile,
     writeFileContent
-} from '../../shared/utils/file_system.util';
-import logger from '../../shared/utils/logger.util';
-import { appConfig } from '../config/app.config';
-import { processMetadataGeneration } from '../utils/prompt_analyzer.util';
-import { dumpYamlContent, sanitizeYamlContent } from '../utils/yaml_operations.util';
+} from '../../shared/utils/file-system';
+import logger from '../../shared/utils/logger';
+import { appConfig } from '../config/app-config';
+import { processMetadataGeneration } from '../utils/metadata-generator';
+import { dumpYamlContent, sanitizeYamlContent } from '../utils/yaml-operations';
 
-export async function generateMetadata(promptContent: string): Promise<Metadata> {
+export async function generateMetadata(promptContent: string): Promise<PromptMetadata> {
     logger.info('Starting metadata generation');
 
     try {
@@ -32,7 +32,7 @@ export async function generateMetadata(promptContent: string): Promise<Metadata>
 }
 
 export async function shouldUpdateMetadata(promptFile: string, metadataFile: string): Promise<[boolean, string]> {
-    const forceRegenerate = appConfig.FORCE_REGENERATE === 'true';
+    const forceRegenerate = appConfig.FORCE_REGENERATE;
     const promptContent = await readFileContent(promptFile);
     const promptHash = crypto.createHash('md5').update(promptContent).digest('hex');
 
@@ -56,8 +56,9 @@ export async function shouldUpdateMetadata(promptFile: string, metadataFile: str
         }
 
         const storedHash = storedHashLine.split(':')[1].trim();
+        const hashesMatch = promptHash === storedHash;
 
-        if (promptHash !== storedHash) {
+        if (!hashesMatch) {
             logger.info(`Content hash mismatch for ${promptFile}. Update needed.`);
             return [true, promptHash];
         }
@@ -91,12 +92,12 @@ export async function updateMetadataHash(metadataFile: string, newHash: string):
 }
 
 export async function updatePromptMetadata(): Promise<void> {
-    logger.info('Starting update_prompt_metadata process');
+    logger.info('Starting update-metadata process');
 
     try {
         await processMainPrompt(appConfig.PROMPTS_DIR);
         await processPromptDirectories(appConfig.PROMPTS_DIR);
-        logger.info('update_prompt_metadata process completed');
+        logger.info('update-metadata process completed');
     } catch (error) {
         logger.error('Error in updatePromptMetadata:', error);
         throw error;
@@ -201,16 +202,16 @@ async function updatePromptDirectory(
         if (await fileExists(newDirPath)) {
             logger.warn(`Directory ${newDirName} already exists. Updating contents.`);
             const files = await readDirectory(currentItemPath);
-            await Promise.all(
-                files.map(async (file) => {
-                    const src = path.join(currentItemPath, file);
-                    const dst = path.join(newDirPath, file);
-
-                    if (await isFile(src)) {
-                        await copyFile(src, dst);
-                    }
-                })
-            );
+
+            for (const file of files) {
+                const src = path.join(currentItemPath, file);
+                const dst = path.join(newDirPath, file);
+
+                if (await isFile(src)) {
+                    await copyFile(src, dst);
+                }
+            }
+
             await removeDirectory(currentItemPath);
         } else {
             await renameFile(currentItemPath, newDirPath);
diff --git a/src/app/core/update_views.ts b/src/app/controllers/update-views.ts
similarity index 82%
rename from src/app/core/update_views.ts
rename to src/app/controllers/update-views.ts
index c17de1b..0c28465 100644
--- a/src/app/core/update_views.ts
+++ b/src/app/controllers/update-views.ts
@@ -2,13 +2,13 @@ import * as path from 'path';
 
 import * as nunjucks from 'nunjucks';
 
-import { commonConfig } from '../../shared/config/common.config';
-import { CategoryItem, Metadata } from '../../shared/types';
-import { isDirectory, readDirectory, readFileContent, writeFileContent } from '../../shared/utils/file_system.util';
-import logger from '../../shared/utils/logger.util';
-import { formatTitleCase } from '../../shared/utils/string_formatter.util';
-import { appConfig } from '../config/app.config';
-import { parseYamlContent } from '../utils/yaml_operations.util';
+import { commonConfig } from '../../shared/config/common-config';
+import { CategoryItem, PromptMetadata } from '../../shared/types';
+import { isDirectory, readDirectory, readFileContent, writeFileContent } from '../../shared/utils/file-system';
+import logger from '../../shared/utils/logger';
+import { formatTitleCase } from '../../shared/utils/string-formatter';
+import { appConfig } from '../config/app-config';
+import { parseYamlContent } from '../utils/yaml-operations';
 
 async function processPromptDirectory(promptDir: string, categories: Record<string, CategoryItem[]>): Promise<void> {
     const promptPath = path.join(appConfig.PROMPTS_DIR, promptDir);
@@ -26,7 +26,7 @@ async function processPromptDirectory(promptDir: string, categories: Record<stri
             readFileContent(promptFile),
             readFileContent(metadataFile)
         ]);
-        const metadata = parseYamlContent(metadataContent) as Metadata;
+        const metadata = parseYamlContent(metadataContent) as PromptMetadata;
         logger.debug(`Read metadata from ${metadataFile}`);
 
         await generateViewFile(promptPath, metadata, promptContent);
@@ -36,7 +36,7 @@ async function processPromptDirectory(promptDir: string, categories: Record<stri
     }
 }
 
-async function generateViewFile(promptPath: string, metadata: Metadata, promptContent: string): Promise<void> {
+async function generateViewFile(promptPath: string, metadata: PromptMetadata, promptContent: string): Promise<void> {
     try {
         const viewContent = nunjucks.render(appConfig.VIEW_TEMPLATE_NAME, {
             metadata,
@@ -57,7 +57,7 @@ async function generateViewFile(promptPath: string, metadata: Metadata, promptCo
 function addPromptToCategories(
     categories: Record<string, CategoryItem[]>,
     promptDir: string,
-    metadata: Metadata
+    metadata: PromptMetadata
 ): void {
     const primaryCategory = metadata.primary_category || appConfig.DEFAULT_CATEGORY;
     categories[primaryCategory] = categories[primaryCategory] || [];
@@ -73,7 +73,7 @@ function addPromptToCategories(
 }
 
 export async function updateViews(): Promise<void> {
-    logger.info('Starting update_views process');
+    logger.info('Starting update-views process');
     const categories: Record<string, CategoryItem[]> = {};
 
     try {
@@ -84,9 +84,8 @@ export async function updateViews(): Promise<void> {
         logger.info(`Iterating through prompts in ${appConfig.PROMPTS_DIR}`);
         const promptDirs = await readDirectory(appConfig.PROMPTS_DIR);
         await Promise.all(promptDirs.map((promptDir) => processPromptDirectory(promptDir, categories)));
-
         await generateReadme(categories);
-        logger.info('update_views process completed');
+        logger.info('update-views process completed');
     } catch (error) {
         logger.error('Error in updateViews:', error);
         throw error;
@@ -99,6 +98,7 @@ async function generateReadme(categories: Record<string, CategoryItem[]>): Promi
             Object.entries(categories)
                 .filter(([, v]) => v.length > 0)
                 .sort(([a], [b]) => a.localeCompare(b))
+                .map(([category, items]) => [category, items.sort((a, b) => a.title.localeCompare(b.title))])
         );
         logger.info('Generating README content');
         const readmeContent = nunjucks.render(appConfig.README_TEMPLATE_NAME, {
diff --git a/src/app/templates/main_readme.md b/src/app/templates/main-readme.md
similarity index 100%
rename from src/app/templates/main_readme.md
rename to src/app/templates/main-readme.md
diff --git a/src/app/templates/sub_readme.md b/src/app/templates/sub-readme.md
similarity index 100%
rename from src/app/templates/sub_readme.md
rename to src/app/templates/sub-readme.md
diff --git a/src/app/utils/__tests__/analyze-prompt.test.ts b/src/app/utils/__tests__/analyze-prompt.test.ts
new file mode 100644
index 0000000..c6b9d3b
--- /dev/null
+++ b/src/app/utils/__tests__/analyze-prompt.test.ts
@@ -0,0 +1,61 @@
+import logger from '../../../shared/utils/logger';
+import { analyzePrompt } from '../analyze-prompt';
+import { processMetadataGeneration } from '../metadata-generator';
+
+jest.mock('../metadata-generator', () => ({
+    processMetadataGeneration: jest.fn()
+}));
+jest.mock('../../../shared/utils/logger', () => ({
+    info: jest.fn(),
+    error: jest.fn(),
+    warn: jest.fn()
+}));
+
+describe('AnalyzePromptUtils', () => {
+    const mockPromptContent = 'Test prompt content';
+    const mockMetadata = {
+        title: 'Test Title',
+        description: 'Detailed description',
+        primary_category: 'Test Category',
+        subcategories: ['sub1', 'sub2'],
+        directory: 'test-dir',
+        tags: ['tag1', 'tag2'],
+        one_line_description: 'Test description',
+        variables: [
+            {
+                name: 'var1',
+                type: 'string',
+                role: 'system',
+                optional_for_user: false
+            }
+        ],
+        content_hash: 'hash123',
+        fragments: [
+            {
+                name: 'fragment1',
+                category: 'test',
+                variable: 'TEST_VAR'
+            }
+        ]
+    };
+    beforeEach(() => {
+        jest.clearAllMocks();
+    });
+
+    it('should analyze prompt successfully', async () => {
+        (processMetadataGeneration as jest.Mock).mockResolvedValueOnce(mockMetadata);
+
+        const result = await analyzePrompt(mockPromptContent);
+        expect(result).toEqual(mockMetadata);
+        expect(logger.info).toHaveBeenCalledWith('Starting prompt analysis');
+        expect(logger.info).toHaveBeenCalledWith('Prompt analysis completed successfully');
+    });
+
+    it('should handle errors during analysis', async () => {
+        const error = new Error('Analysis failed');
+        (processMetadataGeneration as jest.Mock).mockRejectedValueOnce(error);
+
+        await expect(analyzePrompt(mockPromptContent)).rejects.toThrow('Analysis failed');
+        expect(logger.error).toHaveBeenCalledWith('Error analyzing prompt:', error);
+    });
+});
diff --git a/src/app/utils/__tests__/fragment-manager.test.ts b/src/app/utils/__tests__/fragment-manager.test.ts
new file mode 100644
index 0000000..e117503
--- /dev/null
+++ b/src/app/utils/__tests__/fragment-manager.test.ts
@@ -0,0 +1,77 @@
+import { readDirectory, isDirectory } from '../../../shared/utils/file-system';
+import logger from '../../../shared/utils/logger';
+import { listAvailableFragments } from '../fragment-manager';
+
+jest.mock('../../../shared/utils/file-system');
+jest.mock('../../../shared/utils/logger');
+jest.mock('../../config/app-config', () => ({
+    appConfig: {
+        FRAGMENTS_DIR: '/mock/fragments/dir'
+    }
+}));
+
+describe('FragmentManagerUtils', () => {
+    beforeEach(() => {
+        jest.clearAllMocks();
+    });
+
+    it('should list fragments from all categories', async () => {
+        const mockReadDirectory = readDirectory as jest.MockedFunction<typeof readDirectory>;
+        const mockIsDirectory = isDirectory as jest.MockedFunction<typeof isDirectory>;
+        mockReadDirectory.mockImplementationOnce(async () => ['category1', 'category2']);
+
+        mockReadDirectory
+            .mockImplementationOnce(async () => ['fragment1.js', 'fragment2.js'])
+            .mockImplementationOnce(async () => ['fragment3.js']);
+
+        mockIsDirectory.mockImplementation(async () => true);
+
+        const result = await listAvailableFragments();
+        const parsed = JSON.parse(result);
+        expect(parsed).toEqual({
+            category1: ['fragment1', 'fragment2'],
+            category2: ['fragment3']
+        });
+
+        expect(logger.info).toHaveBeenCalledWith('Listing available fragments');
+        expect(logger.info).toHaveBeenCalledWith('Listed fragments from 2 categories');
+    });
+
+    it('should skip non-directory entries', async () => {
+        const mockReadDirectory = readDirectory as jest.MockedFunction<typeof readDirectory>;
+        const mockIsDirectory = isDirectory as jest.MockedFunction<typeof isDirectory>;
+        mockReadDirectory.mockImplementationOnce(async () => ['category1', 'not-a-dir']);
+        mockReadDirectory.mockImplementationOnce(async () => ['fragment1.js']);
+
+        mockIsDirectory.mockImplementationOnce(async () => true).mockImplementationOnce(async () => false);
+
+        const result = await listAvailableFragments();
+        const parsed = JSON.parse(result);
+        expect(parsed).toEqual({
+            category1: ['fragment1']
+        });
+    });
+
+    it('should handle empty categories', async () => {
+        const mockReadDirectory = readDirectory as jest.MockedFunction<typeof readDirectory>;
+        const mockIsDirectory = isDirectory as jest.MockedFunction<typeof isDirectory>;
+        mockReadDirectory.mockImplementationOnce(async () => ['empty-category']);
+        mockReadDirectory.mockImplementationOnce(async () => []);
+        mockIsDirectory.mockImplementation(async () => true);
+
+        const result = await listAvailableFragments();
+        const parsed = JSON.parse(result);
+        expect(parsed).toEqual({
+            'empty-category': []
+        });
+    });
+
+    it('should handle errors and log them', async () => {
+        const mockReadDirectory = readDirectory as jest.MockedFunction<typeof readDirectory>;
+        const error = new Error('Test error');
+        mockReadDirectory.mockRejectedValue(error);
+
+        await expect(listAvailableFragments()).rejects.toThrow('Test error');
+        expect(logger.error).toHaveBeenCalledWith('Error listing available fragments:', error);
+    });
+});
diff --git a/src/app/utils/__tests__/metadata-generator.test.ts b/src/app/utils/__tests__/metadata-generator.test.ts
new file mode 100644
index 0000000..f997ec0
--- /dev/null
+++ b/src/app/utils/__tests__/metadata-generator.test.ts
@@ -0,0 +1,114 @@
+import { readFileContent } from '../../../shared/utils/file-system';
+import logger from '../../../shared/utils/logger';
+import { processPromptContent } from '../../../shared/utils/prompt-processing';
+import { appConfig } from '../../config/app-config';
+import { listAvailableFragments } from '../fragment-manager';
+import { loadAnalyzerPrompt, processMetadataGeneration } from '../metadata-generator';
+import { parseYamlContent } from '../yaml-operations';
+
+jest.mock('../fragment-manager');
+jest.mock('../yaml-operations');
+jest.mock('../../../shared/utils/file-system');
+jest.mock('../../../shared/utils/prompt-processing', () => ({
+    processPromptContent: jest.fn(),
+    updatePromptWithVariables: jest.fn()
+}));
+jest.mock('../../config/app-config', () => ({
+    appConfig: {
+        ANALYZER_PROMPT_PATH: '/mock/analyzer/prompt.txt'
+    }
+}));
+jest.mock('../analyze-prompt', () => ({
+    analyzePrompt: jest.fn()
+}));
+jest.mock('../../../shared/utils/logger', () => ({
+    info: jest.fn(),
+    error: jest.fn(),
+    warn: jest.fn()
+}));
+
+describe('MetadataGeneratorUtils', () => {
+    beforeEach(() => {
+        jest.clearAllMocks();
+    });
+
+    describe('loadAnalyzerPrompt', () => {
+        it('should load analyzer prompt successfully', async () => {
+            const mockContent = 'Mock analyzer prompt content';
+            (readFileContent as jest.Mock).mockResolvedValue(mockContent);
+
+            const result = await loadAnalyzerPrompt();
+            expect(result).toBe(mockContent);
+            expect(readFileContent).toHaveBeenCalledWith(appConfig.ANALYZER_PROMPT_PATH);
+            expect(logger.info).toHaveBeenCalledWith(expect.stringContaining('Loading analyzer prompt'));
+        });
+
+        it('should handle errors when loading analyzer prompt', async () => {
+            const error = new Error('Failed to read file');
+            (readFileContent as jest.Mock).mockRejectedValue(error);
+
+            await expect(loadAnalyzerPrompt()).rejects.toThrow('Failed to read file');
+            expect(logger.error).toHaveBeenCalledWith('Error loading analyzer prompt:', error);
+        });
+    });
+
+    describe('processMetadataGeneration', () => {
+        const mockPromptContent = 'Test prompt content';
+        const mockAnalyzerPrompt = 'Analyzer prompt';
+        const mockFragments = '{"category": ["fragment1"]}';
+        const mockProcessedContent = '<output>yaml: content</output>';
+        const mockParsedMetadata = {
+            title: 'Test Title',
+            primary_category: 'Test Category',
+            subcategories: ['sub1', 'sub2'],
+            directory: 'test-dir',
+            tags: ['tag1', 'tag2'],
+            one_line_description: 'Test description',
+            description: 'Detailed description',
+            variables: [
+                {
+                    name: 'var1',
+                    type: 'string',
+                    role: 'system',
+                    optional_for_user: false
+                }
+            ],
+            content_hash: 'hash123',
+            fragments: [
+                {
+                    name: 'fragment1',
+                    category: 'test',
+                    variable: 'TEST_VAR'
+                }
+            ]
+        };
+        beforeEach(() => {
+            (readFileContent as jest.Mock).mockResolvedValue(mockAnalyzerPrompt);
+            (listAvailableFragments as jest.Mock).mockResolvedValue(mockFragments);
+            (processPromptContent as jest.Mock).mockResolvedValue(mockProcessedContent);
+            (parseYamlContent as jest.Mock).mockReturnValue(mockParsedMetadata);
+        });
+
+        it('should generate metadata successfully', async () => {
+            const result = await processMetadataGeneration(mockPromptContent);
+            expect(result).toEqual(mockParsedMetadata);
+            expect(listAvailableFragments).toHaveBeenCalled();
+            expect(processPromptContent).toHaveBeenCalled();
+            expect(parseYamlContent).toHaveBeenCalled();
+        });
+
+        it('should throw error for invalid metadata', async () => {
+            const invalidMetadata = { ...mockParsedMetadata, title: '' };
+            (parseYamlContent as jest.Mock).mockReturnValue(invalidMetadata);
+
+            await expect(processMetadataGeneration(mockPromptContent)).rejects.toThrow('Invalid metadata generated');
+        });
+
+        it('should handle missing output tags', async () => {
+            (processPromptContent as jest.Mock).mockResolvedValue('content without tags');
+            await processMetadataGeneration(mockPromptContent);
+
+            expect(logger.warn).toHaveBeenCalledWith('Output tags not found in content, returning trimmed content');
+        });
+    });
+});
diff --git a/src/app/utils/__tests__/prompt-analyzer-cli.test.ts b/src/app/utils/__tests__/prompt-analyzer-cli.test.ts
new file mode 100644
index 0000000..b0767c1
--- /dev/null
+++ b/src/app/utils/__tests__/prompt-analyzer-cli.test.ts
@@ -0,0 +1,83 @@
+import { readFileContent } from '../../../shared/utils/file-system';
+import { analyzePrompt } from '../analyze-prompt';
+import { runPromptAnalyzerFromCLI } from '../prompt-analyzer-cli';
+
+jest.mock('../../../shared/utils/file-system');
+jest.mock('../analyze-prompt', () => ({
+    analyzePrompt: jest.fn()
+}));
+
+describe('PromptAnalyzerCLIUtils', () => {
+    beforeEach(() => {
+        jest.clearAllMocks();
+    });
+
+    describe('runPromptAnalyzerFromCLI', () => {
+        let mockExit: jest.SpyInstance;
+        beforeEach(() => {
+            jest.spyOn(console, 'error').mockImplementation(() => {});
+            jest.spyOn(console, 'log').mockImplementation(() => {});
+            mockExit = jest
+                .spyOn(process, 'exit')
+                .mockImplementation((_code?: number | string | null | undefined): never => undefined as never);
+        });
+
+        afterEach(() => {
+            (console.error as jest.Mock).mockRestore();
+            (console.log as jest.Mock).mockRestore();
+            mockExit.mockRestore();
+        });
+
+        it('should read prompt file and analyze prompt', async () => {
+            const mockPromptPath = '/path/to/prompt.txt';
+            const mockPromptContent = 'Test prompt content';
+            const mockMetadata = {
+                title: 'Test Title',
+                description: 'Detailed description',
+                primary_category: 'Test Category',
+                subcategories: ['sub1', 'sub2'],
+                directory: 'test-dir',
+                tags: ['tag1', 'tag2'],
+                one_line_description: 'Test description',
+                variables: [
+                    {
+                        name: 'var1',
+                        type: 'string',
+                        role: 'system',
+                        optional_for_user: false
+                    }
+                ],
+                content_hash: 'hash123',
+                fragments: [
+                    {
+                        name: 'fragment1',
+                        category: 'test',
+                        variable: 'TEST_VAR'
+                    }
+                ]
+            };
+            (readFileContent as jest.Mock).mockResolvedValueOnce(mockPromptContent);
+            (analyzePrompt as jest.Mock).mockResolvedValueOnce(mockMetadata);
+
+            await runPromptAnalyzerFromCLI([mockPromptPath]);
+
+            expect(readFileContent).toHaveBeenCalledWith(mockPromptPath);
+            expect(analyzePrompt).toHaveBeenCalledWith(mockPromptContent);
+            expect(console.log).toHaveBeenCalledWith('Generated Metadata:');
+            expect(console.log).toHaveBeenCalledWith(JSON.stringify(mockMetadata, null, 2));
+
+            expect(mockExit).toHaveBeenCalledWith(0);
+        });
+
+        it('should handle errors during processing', async () => {
+            const mockPromptPath = '/path/to/prompt.txt';
+            const error = new Error('Test error');
+            (readFileContent as jest.Mock).mockRejectedValue(error);
+
+            await runPromptAnalyzerFromCLI([mockPromptPath]);
+
+            expect(console.error).toHaveBeenCalledWith('Error:', error);
+            expect(mockExit).toHaveBeenCalledWith(1);
+        });
+    });
+});
diff --git a/src/app/utils/__tests__/yaml-operations.test.ts b/src/app/utils/__tests__/yaml-operations.test.ts
new file mode 100644
index 0000000..27bb2a4
--- /dev/null
+++ b/src/app/utils/__tests__/yaml-operations.test.ts
@@ -0,0 +1,203 @@
+import * as yaml from 'js-yaml';
+
+import { PromptMetadata } from '../../../shared/types';
+import logger from '../../../shared/utils/logger';
+import { appConfig } from '../../config/app-config';
+import {
+    parseYamlContent,
+    dumpYamlContent,
+    isValidMetadata,
+    parseAndValidateYamlContent,
+    sanitizeYamlContent,
+    needsSanitization
+} from '../yaml-operations';
+
+jest.mock('../../../shared/utils/logger', () => ({
+    debug: jest.fn(),
+    error: jest.fn(),
+    warn: jest.fn()
+}));
+jest.mock('js-yaml', () => {
+    const originalModule = jest.requireActual('js-yaml');
+    return {
+        ...originalModule,
+        dump: jest.fn(originalModule.dump)
+    };
+});
+
+describe('YAMLOperationsUtils', () => {
+    const mockValidMetadata: PromptMetadata = {
+        title: 'Test Title',
+        primary_category: 'Test Category',
+        subcategories: ['sub1', 'sub2'],
+        directory: 'test-dir',
+        tags: ['tag1', 'tag2'],
+        one_line_description: 'Test description',
+        description: 'Detailed description',
+        variables: [
+            {
+                name: 'var1',
+                role: 'system',
+                optional_for_user: false
+            }
+        ]
+    };
+    afterEach(() => {
+        jest.clearAllMocks();
+    });
+
+    describe('parseYamlContent', () => {
+        it('should parse valid YAML content', () => {
+            const yamlString = yaml.dump(mockValidMetadata);
+            const result = parseYamlContent(yamlString);
+            expect(result).toEqual(mockValidMetadata);
+        });
+
+        it('should handle XML-like wrapped content', () => {
+            const wrappedContent = `<yaml>\n${yaml.dump(mockValidMetadata)}</yaml>`;
+            const result = parseYamlContent(wrappedContent);
+            expect(result).toEqual(mockValidMetadata);
+        });
+
+        it('should throw error for invalid YAML', () => {
+            const invalidYaml = '{\n  invalid: yaml: content:';
+            expect(() => parseYamlContent(invalidYaml)).toThrow();
+        });
+    });
+
+    describe('dumpYamlContent', () => {
+        it('should dump metadata to YAML format', () => {
+            const result = dumpYamlContent(mockValidMetadata);
+            const parsed = yaml.load(result) as PromptMetadata;
+            expect(parsed).toEqual(mockValidMetadata);
+        });
+
+        it('should use configured indent and line width', () => {
+            const result = dumpYamlContent(mockValidMetadata);
+            const lines = result.split('\n');
+            const indentMatch = lines.some((line) => line.startsWith(' '.repeat(appConfig.YAML_INDENT)));
+            expect(indentMatch).toBeTruthy();
+        });
+
+        it('should throw error for invalid input', () => {
+            const invalidInput = {
+                circular: {}
+            };
+            invalidInput.circular = invalidInput;
+            expect(() => dumpYamlContent(invalidInput as any)).toThrow();
+        });
+    });
+
+    describe('isValidMetadata', () => {
+        it('should validate correct metadata', () => {
+            expect(isValidMetadata(mockValidMetadata)).toBeTruthy();
+        });
+
+        it('should reject null input', () => {
+            expect(isValidMetadata(null)).toBeFalsy();
+        });
+
+        it('should reject missing required fields', () => {
+            const invalidMetadata = { ...mockValidMetadata };
+            delete (invalidMetadata as any).title;
+            expect(isValidMetadata(invalidMetadata)).toBeFalsy();
+        });
+
+        it('should reject invalid variable structure', () => {
+            const invalidMetadata = {
+                ...mockValidMetadata,
+                variables: [{ invalid: 'structure' }]
+            };
+            expect(isValidMetadata(invalidMetadata)).toBeFalsy();
+        });
+
+        it('should reject variables that are not objects', () => {
+            const invalidMetadata = {
+                ...mockValidMetadata,
+                variables: [null]
+            };
+            expect(isValidMetadata(invalidMetadata)).toBeFalsy();
+        });
+    });
+
+    describe('parseAndValidateYamlContent', () => {
+        it('should parse and validate correct YAML', () => {
+            const yamlString = yaml.dump(mockValidMetadata);
+            const result = parseAndValidateYamlContent(yamlString);
+            expect(result).toEqual(mockValidMetadata);
+        });
+
+        it('should throw error for invalid metadata structure', () => {
+            const invalidYaml = yaml.dump({ invalid: 'structure' });
+            expect(() => parseAndValidateYamlContent(invalidYaml)).toThrow();
+        });
+    });
+
+    describe('sanitizeYamlContent', () => {
+        it('should handle simple key-value content', () => {
+            const content = 'content_hash: abc123\n';
+            const result = sanitizeYamlContent(content);
+            expect(result).toBe(content);
+        });
+
+        it('should sanitize complex YAML content', () => {
+            const messyYaml = yaml.dump(mockValidMetadata).replace(/\n/g, '\n\n');
+            const result = sanitizeYamlContent(messyYaml);
+            expect(result).toBe(
+                yaml
+                    .dump(mockValidMetadata, {
+                        indent: appConfig.YAML_INDENT,
+                        lineWidth: appConfig.YAML_LINE_WIDTH,
+                        noRefs: true,
+                        sortKeys: true
+                    })
+                    .trim() + '\n'
+            );
+        });
+
+        it('should handle JSON content', () => {
+            const jsonContent = JSON.stringify(mockValidMetadata);
+            const result = sanitizeYamlContent(jsonContent);
+            expect(() => yaml.load(result)).not.toThrow();
+        });
+
+        it('should return content as-is if both JSON and YAML parsing fail', () => {
+            const invalidContent = 'not valid yaml or json';
+            const result = sanitizeYamlContent(invalidContent);
+            expect(result).toBe(invalidContent.trim() + '\n');
+        });
+
+        it('should throw error when dumping fails in sanitizeYamlContent', () => {
+            const content = 'valid: yaml';
+            (yaml.dump as jest.Mock).mockImplementationOnce(() => {
+                throw new Error('Dumping failed');
+            });
+
+            expect(() => sanitizeYamlContent(content)).toThrow('Dumping failed');
+        });
+    });
+
+    describe('needsSanitization', () => {
+        it('should detect content needing sanitization', () => {
+            const messyYaml = yaml.dump(mockValidMetadata).replace(/\n/g, '\n\n');
+            expect(needsSanitization(messyYaml)).toBeTruthy();
+        });
+
+        it('should pass already sanitized content', () => {
+            const cleanYaml = yaml.dump(mockValidMetadata, {
+                indent: appConfig.YAML_INDENT,
+                lineWidth: appConfig.YAML_LINE_WIDTH,
+                noRefs: true,
+                sortKeys: true
+            });
+            expect(needsSanitization(cleanYaml)).toBeFalsy();
+        });
+
+        it('should return true for invalid YAML content needing sanitization', () => {
+            const invalidYaml = 'invalid: yaml: content';
+            const result = needsSanitization(invalidYaml);
+            expect(result).toBeTruthy();
+            expect(logger.error).toHaveBeenCalledWith('Error checking YAML sanitization:', expect.any(Error));
+        });
+    });
+});
diff --git a/src/app/utils/analyze-prompt.ts b/src/app/utils/analyze-prompt.ts
new file mode 100644
index 0000000..2f23d43
--- /dev/null
+++ b/src/app/utils/analyze-prompt.ts
@@ -0,0 +1,15 @@
+import { processMetadataGeneration } from './metadata-generator';
+import { PromptMetadata } from '../../shared/types';
+import logger from '../../shared/utils/logger';
+
+export async function analyzePrompt(promptContent: string): Promise<PromptMetadata> {
+    try {
+        logger.info('Starting prompt analysis');
+        const metadata = await processMetadataGeneration(promptContent);
+        logger.info('Prompt analysis completed successfully');
+        return metadata;
+    } catch (error) {
+        logger.error('Error analyzing prompt:', error);
+        throw error;
+    }
+}
diff --git a/src/app/utils/fragment_manager.util.ts b/src/app/utils/fragment-manager.ts
similarity index 90%
rename from src/app/utils/fragment_manager.util.ts
rename to src/app/utils/fragment-manager.ts
index fbda61a..58dd2ba 100644
--- a/src/app/utils/fragment_manager.util.ts
+++ b/src/app/utils/fragment-manager.ts
@@ -1,8 +1,8 @@
 import path from 'path';
 
-import { isDirectory, readDirectory } from '../../shared/utils/file_system.util';
-import logger from '../../shared/utils/logger.util';
-import { appConfig } from '../config/app.config';
+import { isDirectory, readDirectory } from '../../shared/utils/file-system';
+import logger from '../../shared/utils/logger';
+import { appConfig } from '../config/app-config';
 
 export async function listAvailableFragments(): Promise<string> {
     try {
diff --git a/src/app/utils/prompt_analyzer.util.ts b/src/app/utils/metadata-generator.ts
similarity index 66%
rename from src/app/utils/prompt_analyzer.util.ts
rename to src/app/utils/metadata-generator.ts
index 4fda4e5..aa98a76 100644
--- a/src/app/utils/prompt_analyzer.util.ts
+++ b/src/app/utils/metadata-generator.ts
@@ -1,10 +1,10 @@
-import { listAvailableFragments } from './fragment_manager.util';
-import { parseYamlContent } from './yaml_operations.util';
-import { Metadata } from '../../shared/types';
-import { readFileContent } from '../../shared/utils/file_system.util';
-import logger from '../../shared/utils/logger.util';
-import { processPromptContent, updatePromptWithVariables } from '../../shared/utils/prompt_processing.util';
-import { appConfig } from '../config/app.config';
+import { listAvailableFragments } from './fragment-manager';
+import { parseYamlContent } from './yaml-operations';
+import { PromptMetadata } from '../../shared/types';
+import { readFileContent } from '../../shared/utils/file-system';
+import logger from '../../shared/utils/logger';
+import { processPromptContent, updatePromptWithVariables } from '../../shared/utils/prompt-processing';
+import { appConfig } from '../config/app-config';
 
 export async function loadAnalyzerPrompt(): Promise<string> {
     try {
@@ -18,7 +18,7 @@ export async function loadAnalyzerPrompt(): Promise<string> {
     }
 }
 
-export async function processMetadataGeneration(promptContent: string): Promise<Metadata> {
+export async function processMetadataGeneration(promptContent: string): Promise<PromptMetadata> {
     logger.info('Processing prompt for metadata generation');
 
     try {
@@ -34,7 +34,7 @@ export async function processMetadataGeneration(promptContent: string): Promise<
         const content = await processPromptContent([{ role: 'user', content: updatedPromptContent }], false);
         const yamlContent = extractOutputContent(content);
         const parsedMetadata = parseYamlContent(yamlContent);
-        const metadata: Metadata = {
+        const metadata: PromptMetadata = {
             title: parsedMetadata.title || '',
             primary_category: parsedMetadata.primary_category || '',
             subcategories: parsedMetadata.subcategories || [],
@@ -68,7 +68,7 @@ function extractOutputContent(content: string): string {
     return content.slice(outputStart + 8, outputEnd).trim();
 }
 
-function isValidMetadata(metadata: Metadata): boolean {
+function isValidMetadata(metadata: PromptMetadata): boolean {
     if (!metadata.title || !metadata.description || !metadata.primary_category) {
         logger.warn('Missing one or more required fields in metadata: title, description, or primary_category');
         return false;
@@ -80,36 +80,3 @@ function isValidMetadata(metadata: Metadata): boolean {
     }
     return true;
 }
-
-export async function analyzePrompt(promptContent: string): Promise<Metadata> {
-    try {
-        logger.info('Starting prompt analysis');
-        const metadata = await processMetadataGeneration(promptContent);
-        logger.info('Prompt analysis completed successfully');
-        return metadata;
-    } catch (error) {
-        logger.error('Error analyzing prompt:', error);
-        throw error;
-    }
-}
-
-if (require.main === module) {
-    // This block will be executed if the script is run directly
-    const promptPath = process.argv[2];
-
-    if (!promptPath) {
-        console.error('Please provide a path to the prompt file as an argument');
-        process.exit(1);
-    }
-
-    readFileContent(promptPath)
-        .then(analyzePrompt)
-        .then((metadata) => {
-            console.log('Generated Metadata:');
-            console.log(JSON.stringify(metadata, null, 2));
-        })
-        .catch((error) => {
-            console.error('Error:', error);
-            process.exit(1);
-        });
-}
diff --git a/src/app/utils/prompt-analyzer-cli.ts b/src/app/utils/prompt-analyzer-cli.ts
new file mode 100644
index 0000000..f00b8d2
--- /dev/null
+++ b/src/app/utils/prompt-analyzer-cli.ts
@@ -0,0 +1,26 @@
+import { analyzePrompt } from './analyze-prompt';
+import { readFileContent } from '../../shared/utils/file-system';
+
+export async function runPromptAnalyzerFromCLI(args: string[]): Promise<void> {
+    const promptPath = args[0];
+
+    if (!promptPath) {
+        console.error('Please provide a path to the prompt file as an argument');
+        process.exit(1);
+    }
+
+    try {
+        const promptContent = await readFileContent(promptPath);
+        const metadata = await analyzePrompt(promptContent);
+        console.log('Generated Metadata:');
+        console.log(JSON.stringify(metadata, null, 2));
+        process.exit(0);
+    } catch (error) {
+        console.error('Error:', error);
+        process.exit(1);
+    }
+}
+
+if (require.main === module) {
+    runPromptAnalyzerFromCLI(process.argv.slice(2));
+}
diff --git a/src/app/utils/yaml_operations.util.ts b/src/app/utils/yaml-operations.ts
similarity index 63%
rename from src/app/utils/yaml_operations.util.ts
rename to src/app/utils/yaml-operations.ts
index 32449b2..82b59b8 100644
--- a/src/app/utils/yaml_operations.util.ts
+++ b/src/app/utils/yaml-operations.ts
@@ -1,21 +1,15 @@
 import * as yaml from 'js-yaml';
 
-import { Metadata, Variable } from '../../shared/types';
-import logger from '../../shared/utils/logger.util';
-import { appConfig } from '../config/app.config';
-
-/**
- * Parses YAML content into a Metadata object.
- * @param {string} yamlContent - The YAML content to parse.
- * @returns {Metadata} The parsed Metadata object.
- * @throws {Error} If parsing fails.
- */
-export function parseYamlContent(yamlContent: string): Metadata {
+import { PromptMetadata, Variable } from '../../shared/types';
+import logger from '../../shared/utils/logger';
+import { appConfig } from '../config/app-config';
+
+export function parseYamlContent(yamlContent: string): PromptMetadata {
     try {
         logger.debug('Preparing content for YAML parsing');
         yamlContent = yamlContent.replace(/^\s*<[^>]+>\s*([\s\S]*?)\s*<\/[^>]+>\s*$/, '$1');
         logger.debug('Parsing YAML content');
-        const parsedContent = yaml.load(yamlContent) as Metadata;
+        const parsedContent = yaml.load(yamlContent) as PromptMetadata;
         logger.debug('YAML content parsed successfully');
         return parsedContent;
     } catch (error) {
@@ -24,13 +18,7 @@ export function parseYamlContent(yamlContent: string): Metadata {
     }
 }
 
-/**
- * Dumps a Metadata object into a YAML string.
- * @param {Metadata} data - The Metadata object to dump.
- * @returns {string} The YAML string representation of the Metadata.
- * @throws {Error} If dumping fails.
- */
-export function dumpYamlContent(data: Metadata): string {
+export function dumpYamlContent(data: PromptMetadata): string {
     try {
         logger.debug('Dumping Metadata to YAML');
         const yamlString = yaml.dump(data, {
@@ -46,20 +34,15 @@ export function dumpYamlContent(data: Metadata): string {
     }
 }
 
-/**
- * Validates that a parsed YAML object conforms to the Metadata interface.
- * @param {unknown} obj - The object to validate.
- * @returns {obj is Metadata} True if the object is valid Metadata, false otherwise.
- */
-export function isValidMetadata(obj: unknown): obj is Metadata {
-    const metadata = obj as Partial<Metadata>;
+export function isValidMetadata(obj: unknown): obj is PromptMetadata {
+    const metadata = obj as Partial<PromptMetadata>;
 
     if (typeof metadata !== 'object' || metadata === null) {
         logger.error('Invalid Metadata: not an object');
         return false;
     }
 
-    const requiredStringFields: (keyof Metadata)[] = [
+    const requiredStringFields: (keyof PromptMetadata)[] = [
         'title',
         'primary_category',
         'directory',
@@ -74,7 +57,7 @@ export function isValidMetadata(obj: unknown): obj is Metadata {
         }
     }
 
-    const requiredArrayFields: (keyof Metadata)[] = ['subcategories', 'tags', 'variables'];
+    const requiredArrayFields: (keyof PromptMetadata)[] = ['subcategories', 'tags', 'variables'];
 
     for (const field of requiredArrayFields) {
         if (!Array.isArray(metadata[field])) {
@@ -90,11 +73,6 @@ export function isValidMetadata(obj: unknown): obj is Metadata {
     return true;
 }
 
-/**
- * Validates that an object conforms to the Variable interface.
- * @param {unknown} obj - The object to validate.
- * @returns {obj is Variable} True if the object is a valid Variable, false otherwise.
- */
 function isValidVariable(obj: unknown): obj is Variable {
     const variable = obj as Partial<Variable>;
     return (
@@ -105,13 +83,7 @@ function isValidVariable(obj: unknown): obj is Variable {
     );
 }
 
-/**
- * Parses YAML content and validates it as Metadata.
- * @param {string} yamlContent - The YAML content to parse and validate.
- * @returns {Metadata} The validated Metadata object.
- * @throws {Error} If parsing fails or the content is not valid Metadata.
- */
-export function parseAndValidateYamlContent(yamlContent: string): Metadata {
+export function parseAndValidateYamlContent(yamlContent: string): PromptMetadata {
     const parsedContent = parseYamlContent(yamlContent);
 
     if (!isValidMetadata(parsedContent)) {
@@ -121,15 +93,26 @@ export function parseAndValidateYamlContent(yamlContent: string): Metadata {
     return parsedContent;
 }
 
-/**
- * Sanitizes YAML content by removing extra spaces and ensuring proper formatting.
- * @param {string} content - The YAML content to sanitize.
- * @returns {string} Sanitized YAML content.
- */
 export function sanitizeYamlContent(content: string): string {
     try {
         logger.debug('Sanitizing YAML content');
-        const parsedContent = yaml.load(content);
+
+        if (content.includes('content_hash:')) {
+            return content.trim() + '\n';
+        }
+
+        let parsedContent;
+
+        try {
+            parsedContent = JSON.parse(content);
+        } catch {
+            try {
+                parsedContent = yaml.load(content);
+            } catch {
+                return content.trim() + '\n';
+            }
+        }
+
         const sanitizedContent = yaml.dump(parsedContent, {
             indent: appConfig.YAML_INDENT,
             lineWidth: appConfig.YAML_LINE_WIDTH,
@@ -144,11 +127,6 @@ export function sanitizeYamlContent(content: string): string {
     }
 }
 
-/**
- * Determines if a YAML content needs sanitization.
- * @param {string} content - The YAML content to check.
- * @returns {boolean} True if the content needs sanitization, false otherwise.
- */
 export function needsSanitization(content: string): boolean {
     try {
         const originalParsed = yaml.load(content);
@@ -157,7 +135,7 @@ export function needsSanitization(content: string): boolean {
         return JSON.stringify(originalParsed) !== JSON.stringify(sanitizedParsed);
     } catch (error) {
         logger.error('Error checking YAML sanitization:', error);
-        return true; // If we can't parse it, it probably needs sanitization
+        return true;
     }
 }
 
diff --git a/src/cli/commands/base.command.ts b/src/cli/commands/base-command.ts
similarity index 95%
rename from src/cli/commands/base.command.ts
rename to src/cli/commands/base-command.ts
index cf41e3b..aacbad8 100644
--- a/src/cli/commands/base.command.ts
+++ b/src/cli/commands/base-command.ts
@@ -7,10 +7,10 @@ import { Command } from 'commander';
 import fs from 'fs-extra';
 
 import { ApiResult } from '../../shared/types';
-import { cliConfig } from '../cli.config';
-import { ENV_PREFIX, FRAGMENT_PREFIX } from '../cli.constants';
-import { handleApiResult } from '../utils/database.util';
-import { handleError } from '../utils/error.util';
+import { cliConfig } from '../config/cli-config';
+import { ENV_PREFIX, FRAGMENT_PREFIX } from '../constants';
+import { handleApiResult } from '../utils/database';
+import { handleError } from '../utils/errors';
 
 export class BaseCommand extends Command {
     constructor(name: string, description: string) {
diff --git a/src/cli/commands/config.command.ts b/src/cli/commands/config-command.ts
similarity index 98%
rename from src/cli/commands/config.command.ts
rename to src/cli/commands/config-command.ts
index b15ccbb..174f6f9 100644
--- a/src/cli/commands/config.command.ts
+++ b/src/cli/commands/config-command.ts
@@ -1,6 +1,6 @@
 import chalk from 'chalk';
 
-import { BaseCommand } from './base.command';
+import { BaseCommand } from './base-command';
 import { Config, getConfig, setConfig } from '../../shared/config';
 
 class ConfigCommand extends BaseCommand {
diff --git a/src/cli/commands/env.command.ts b/src/cli/commands/env-command.ts
similarity index 96%
rename from src/cli/commands/env.command.ts
rename to src/cli/commands/env-command.ts
index 104ec0f..961c1a4 100644
--- a/src/cli/commands/env.command.ts
+++ b/src/cli/commands/env-command.ts
@@ -1,12 +1,12 @@
 import chalk from 'chalk';
 
-import { BaseCommand } from './base.command';
+import { BaseCommand } from './base-command';
 import { EnvVar, Fragment } from '../../shared/types';
-import { formatTitleCase, formatSnakeCase } from '../../shared/utils/string_formatter.util';
-import { FRAGMENT_PREFIX } from '../cli.constants';
-import { createEnvVar, readEnvVars, updateEnvVar, deleteEnvVar } from '../utils/env.util';
-import { listFragments, viewFragmentContent } from '../utils/fragment_operations.util';
-import { listPrompts, getPromptFiles } from '../utils/prompt_crud.util';
+import { formatTitleCase, formatSnakeCase } from '../../shared/utils/string-formatter';
+import { FRAGMENT_PREFIX } from '../constants';
+import { createEnvVar, readEnvVars, updateEnvVar, deleteEnvVar } from '../utils/env-vars';
+import { listFragments, viewFragmentContent } from '../utils/fragments';
+import { listPrompts, getPromptFiles } from '../utils/prompts';
 
 class EnvCommand extends BaseCommand {
     constructor() {
@@ -209,6 +209,10 @@ class EnvCommand extends BaseCommand {
             const uniqueVariables = new Map<string, { name: string; role: string }>();
 
             for (const prompt of prompts) {
+                if (!prompt.id) {
+                    return [];
+                }
+
                 const details = await this.handleApiResult(
                     await getPromptFiles(prompt.id),
                     `Fetched details for prompt ${prompt.id}`
diff --git a/src/cli/commands/execute.command.ts b/src/cli/commands/execute-command.ts
similarity index 87%
rename from src/cli/commands/execute.command.ts
rename to src/cli/commands/execute-command.ts
index a7fc44c..2679658 100644
--- a/src/cli/commands/execute.command.ts
+++ b/src/cli/commands/execute-command.ts
@@ -2,11 +2,10 @@ import chalk from 'chalk';
 import fs from 'fs-extra';
 import yaml from 'js-yaml';
 
-import { BaseCommand } from './base.command';
-import { Metadata, Prompt, Variable } from '../../shared/types';
-import { processPromptContent, updatePromptWithVariables } from '../../shared/utils/prompt_processing.util';
-import { getPromptFiles } from '../utils/prompt_crud.util';
-import { viewPromptDetails } from '../utils/prompt_display.util';
+import { BaseCommand } from './base-command';
+import { PromptMetadata, Variable } from '../../shared/types';
+import { processPromptContent, updatePromptWithVariables } from '../../shared/utils/prompt-processing';
+import { getPromptFiles, viewPromptDetails } from '../utils/prompts';
 
 class ExecuteCommand extends BaseCommand {
     constructor() {
@@ -156,7 +155,7 @@ Note:
         try {
             const promptContent = await fs.readFile(promptFile, 'utf-8');
             const metadataContent = await fs.readFile(metadataFile, 'utf-8');
-            const metadata = yaml.load(metadataContent) as Metadata;
+            const metadata = yaml.load(metadataContent) as PromptMetadata;
 
             if (inspect) {
                 await this.inspectPrompt(metadata);
@@ -168,7 +167,7 @@ Note:
         }
     }
 
-    private async inspectPrompt(metadata: Metadata): Promise<void> {
+    private async inspectPrompt(metadata: PromptMetadata): Promise<void> {
         try {
             await viewPromptDetails(
                 {
@@ -178,7 +177,7 @@ Note:
                     description: metadata.description,
                     tags: metadata.tags,
                     variables: metadata.variables
-                } as Prompt & { variables: Variable[] },
+                } as PromptMetadata & { variables: Variable[] },
                 true
             );
         } catch (error) {
@@ -188,13 +187,26 @@ Note:
 
     private async executePromptWithMetadata(
         promptContent: string,
-        metadata: Metadata,
+        metadata: PromptMetadata,
         dynamicOptions: Record<string, string>,
         fileInputs: Record<string, string>
     ): Promise<void> {
         try {
             const userInputs: Record<string, string> = {};
 
+            for (const variable of metadata.variables) {
+                if (!variable.optional_for_user && !variable.value) {
+                    const snakeCaseName = variable.name.replace(/[{}]/g, '').toLowerCase();
+                    const hasValue =
+                        (dynamicOptions && snakeCaseName in dynamicOptions) ||
+                        (fileInputs && snakeCaseName in fileInputs);
+
+                    if (!hasValue) {
+                        throw new Error(`Required variable ${snakeCaseName} is not set`);
+                    }
+                }
+            }
+
             for (const variable of metadata.variables) {
                 const snakeCaseName = variable.name.replace(/[{}]/g, '').toLowerCase();
                 let value = dynamicOptions[snakeCaseName];
@@ -205,13 +217,12 @@ Note:
                         console.log(chalk.green(`Loaded file content for ${snakeCaseName}`));
                     } catch (error) {
                         console.error(chalk.red(`Error reading file for ${snakeCaseName}:`, error));
+                        throw new Error(`Failed to read file for ${snakeCaseName}`);
                     }
                 }
 
                 if (value) {
                     userInputs[variable.name] = value;
-                } else if (!variable.optional_for_user) {
-                    throw new Error(`Required variable ${snakeCaseName} is not set.`);
                 }
             }
 
diff --git a/src/cli/commands/flush.command.ts b/src/cli/commands/flush-command.ts
similarity index 92%
rename from src/cli/commands/flush.command.ts
rename to src/cli/commands/flush-command.ts
index 0fa79e0..38e67d6 100644
--- a/src/cli/commands/flush.command.ts
+++ b/src/cli/commands/flush-command.ts
@@ -1,7 +1,7 @@
 import chalk from 'chalk';
 
-import { BaseCommand } from './base.command';
-import { flushData } from '../utils/database.util';
+import { BaseCommand } from './base-command';
+import { flushData } from '../utils/database';
 
 class FlushCommand extends BaseCommand {
     constructor() {
diff --git a/src/cli/commands/fragments.command.ts b/src/cli/commands/fragments-command.ts
similarity index 96%
rename from src/cli/commands/fragments.command.ts
rename to src/cli/commands/fragments-command.ts
index a47869c..0f36130 100644
--- a/src/cli/commands/fragments.command.ts
+++ b/src/cli/commands/fragments-command.ts
@@ -1,9 +1,9 @@
 import chalk from 'chalk';
 
-import { BaseCommand } from './base.command';
+import { BaseCommand } from './base-command';
 import { Fragment } from '../../shared/types';
-import { formatTitleCase } from '../../shared/utils/string_formatter.util';
-import { listFragments, viewFragmentContent } from '../utils/fragment_operations.util';
+import { formatTitleCase } from '../../shared/utils/string-formatter';
+import { listFragments, viewFragmentContent } from '../utils/fragments';
 
 type FragmentMenuAction = 'all' | 'category' | 'back';
 
diff --git a/src/cli/commands/menu.command.ts b/src/cli/commands/menu-command.ts
similarity index 93%
rename from src/cli/commands/menu.command.ts
rename to src/cli/commands/menu-command.ts
index b938d1d..e6ebc1e 100644
--- a/src/cli/commands/menu.command.ts
+++ b/src/cli/commands/menu-command.ts
@@ -1,10 +1,10 @@
 import chalk from 'chalk';
 import { Command } from 'commander';
 
-import { BaseCommand } from './base.command';
+import { BaseCommand } from './base-command';
 import { getConfig } from '../../shared/config';
-import { handleError } from '../utils/error.util';
-import { hasFragments, hasPrompts } from '../utils/file_system.util';
+import { handleError } from '../utils/errors';
+import { hasFragments, hasPrompts } from '../utils/file-system';
 
 type MenuAction = 'sync' | 'prompts' | 'fragments' | 'settings' | 'env' | 'back';
 
diff --git a/src/cli/commands/prompts.command.ts b/src/cli/commands/prompts-command.ts
similarity index 96%
rename from src/cli/commands/prompts.command.ts
rename to src/cli/commands/prompts-command.ts
index 83119c5..d4ee6f6 100644
--- a/src/cli/commands/prompts.command.ts
+++ b/src/cli/commands/prompts-command.ts
@@ -1,14 +1,14 @@
 import chalk from 'chalk';
 
-import { BaseCommand } from './base.command';
-import { CategoryItem, EnvVar, Fragment, Prompt, Variable } from '../../shared/types';
-import { formatTitleCase, formatSnakeCase } from '../../shared/utils/string_formatter.util';
-import { ENV_PREFIX, FRAGMENT_PREFIX } from '../cli.constants';
-import { ConversationManager } from '../utils/conversation_manager.util';
-import { fetchCategories, getPromptDetails, updatePromptVariable } from '../utils/database.util';
-import { readEnvVars } from '../utils/env.util';
-import { listFragments, viewFragmentContent } from '../utils/fragment_operations.util';
-import { viewPromptDetails } from '../utils/prompt_display.util';
+import { BaseCommand } from './base-command';
+import { CategoryItem, EnvVar, Fragment, PromptMetadata, Variable } from '../../shared/types';
+import { formatTitleCase, formatSnakeCase } from '../../shared/utils/string-formatter';
+import { ENV_PREFIX, FRAGMENT_PREFIX } from '../constants';
+import { ConversationManager } from '../utils/conversation-manager';
+import { fetchCategories, getPromptDetails, updatePromptVariable } from '../utils/database';
+import { readEnvVars } from '../utils/env-vars';
+import { listFragments, viewFragmentContent } from '../utils/fragments';
+import { viewPromptDetails } from '../utils/prompts';
 
 type PromptMenuAction = 'all' | 'category' | 'id' | 'back';
 type SelectPromptMenuAction = Variable | 'execute' | 'unset_all' | 'back';
@@ -183,7 +183,7 @@ class PromptCommand extends BaseCommand {
         }
     }
 
-    private async selectPromptAction(details: Prompt & { variables: Variable[] }): Promise<SelectPromptMenuAction> {
+    private async selectPromptAction(details: PromptMetadata): Promise<SelectPromptMenuAction> {
         const choices: Array<{ name: string; value: SelectPromptMenuAction }> = [];
         const allRequiredSet = details.variables.every((v) => v.optional_for_user || v.value);
 
diff --git a/src/cli/commands/settings.command.ts b/src/cli/commands/settings-command.ts
similarity index 89%
rename from src/cli/commands/settings.command.ts
rename to src/cli/commands/settings-command.ts
index 3a8cf18..6e04b45 100644
--- a/src/cli/commands/settings.command.ts
+++ b/src/cli/commands/settings-command.ts
@@ -1,7 +1,7 @@
-import { BaseCommand } from './base.command';
-import ConfigCommand from './config.command';
-import FlushCommand from './flush.command';
-import SyncCommand from './sync.command';
+import { BaseCommand } from './base-command';
+import ConfigCommand from './config-command';
+import FlushCommand from './flush-command';
+import SyncCommand from './sync-command';
 
 type SettingsAction = 'config' | 'sync' | 'flush' | 'back';
 
diff --git a/src/cli/commands/sync.command.ts b/src/cli/commands/sync-command.ts
similarity index 97%
rename from src/cli/commands/sync.command.ts
rename to src/cli/commands/sync-command.ts
index 49b55b1..4bb3cc5 100644
--- a/src/cli/commands/sync.command.ts
+++ b/src/cli/commands/sync-command.ts
@@ -4,11 +4,11 @@ import chalk from 'chalk';
 import fs from 'fs-extra';
 import simpleGit, { SimpleGit } from 'simple-git';
 
-import { BaseCommand } from './base.command';
+import { BaseCommand } from './base-command';
 import { getConfig, setConfig } from '../../shared/config';
-import logger from '../../shared/utils/logger.util';
-import { cliConfig } from '../cli.config';
-import { syncPromptsWithDatabase, cleanupOrphanedData } from '../utils/database.util';
+import logger from '../../shared/utils/logger';
+import { cliConfig } from '../config/cli-config';
+import { syncPromptsWithDatabase, cleanupOrphanedData } from '../utils/database';
 
 class SyncCommand extends BaseCommand {
     constructor() {
diff --git a/src/cli/cli.config.ts b/src/cli/config/cli-config.ts
similarity index 71%
rename from src/cli/cli.config.ts
rename to src/cli/config/cli-config.ts
index 080fe06..4427ee2 100644
--- a/src/cli/cli.config.ts
+++ b/src/cli/config/cli-config.ts
@@ -1,6 +1,6 @@
 import * as path from 'path';
 
-import { CONFIG_DIR } from '../shared/config/config.constants';
+import { CONFIG_DIR } from '../../shared/config/constants';
 
 export interface CliConfig {
     PROMPTS_DIR: string;
@@ -11,8 +11,8 @@ export interface CliConfig {
 }
 
 export const cliConfig: CliConfig = {
-    PROMPTS_DIR: path.join(CONFIG_DIR, 'prompts'),
-    FRAGMENTS_DIR: path.join(CONFIG_DIR, 'fragments'),
+    PROMPTS_DIR: 'prompts',
+    FRAGMENTS_DIR: 'fragments',
     DB_PATH: path.join(CONFIG_DIR, 'prompts.sqlite'),
     TEMP_DIR: path.join(CONFIG_DIR, 'temp'),
     MENU_PAGE_SIZE: process.env.MENU_PAGE_SIZE ? parseInt(process.env.MENU_PAGE_SIZE, 10) : 20
diff --git a/src/cli/cli.constants.ts b/src/cli/constants.ts
similarity index 100%
rename from src/cli/cli.constants.ts
rename to src/cli/constants.ts
diff --git a/src/cli/index.ts b/src/cli/index.ts
index 54b254f..6efd72e 100644
--- a/src/cli/index.ts
+++ b/src/cli/index.ts
@@ -4,16 +4,16 @@ import { Command } from 'commander';
 import dotenv from 'dotenv';
 
 import { getConfigValue, setConfig } from '../shared/config';
-import configCommand from './commands/config.command';
-import envCommand from './commands/env.command';
-import executeCommand from './commands/execute.command';
-import flushCommand from './commands/flush.command';
-import fragmentsCommand from './commands/fragments.command';
-import { showMainMenu } from './commands/menu.command';
-import promptsCommand from './commands/prompts.command';
-import settingsCommand from './commands/settings.command';
-import syncCommand from './commands/sync.command';
-import { initDatabase } from './utils/database.util';
+import configCommand from './commands/config-command';
+import envCommand from './commands/env-command';
+import executeCommand from './commands/execute-command';
+import flushCommand from './commands/flush-command';
+import fragmentsCommand from './commands/fragments-command';
+import { showMainMenu } from './commands/menu-command';
+import promptsCommand from './commands/prompts-command';
+import settingsCommand from './commands/settings-command';
+import syncCommand from './commands/sync-command';
+import { initDatabase } from './utils/database';
 
 process.env.CLI_ENV = 'cli';
 
diff --git a/src/cli/utils/__tests__/__snapshots__/prompts.test.ts.snap b/src/cli/utils/__tests__/__snapshots__/prompts.test.ts.snap
new file mode 100644
index 0000000..c636f79
--- /dev/null
+++ b/src/cli/utils/__tests__/__snapshots__/prompts.test.ts.snap
@@ -0,0 +1,79 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`PromptsUtils viewPromptDetails should display env variable correctly 1`] = `
+"Prompt: Test Prompt
+
+Full test description
+
+Category: Test
+
+Tags: tag1, tag2
+
+Options: ([*] Required  [ ] Optional)
+  --var1 [*] 
+    test role
+      Env: env_var_name (env-value)
+"
+`;
+
+exports[`PromptsUtils viewPromptDetails should display fragment variable correctly 1`] = `
+"Prompt: Test Prompt
+
+Full test description
+
+Category: Test
+
+Tags: tag1, tag2
+
+Options: ([*] Required  [ ] Optional)"
+`;
+
+exports[`PromptsUtils viewPromptDetails should display prompt details correctly 1`] = `
+"Prompt: Test Prompt
+
+Full test description
+
+Category: Test
+
+Tags: tag1, tag2
+
+Options: ([*] Required  [ ] Optional)
+  --var1 [*] (Env variable available)
+    test role
+      Not Set (Required)
+  --var2 [ ] 
+    test role 2
+      Not Set
+"
+`;
+
+exports[`PromptsUtils viewPromptDetails should display regular variable value correctly 1`] = `
+"Prompt: Test Prompt
+
+Full test description
+
+Category: Test
+
+Tags: tag1, tag2
+
+Options: ([*] Required  [ ] Optional)"
+`;
+
+exports[`PromptsUtils viewPromptDetails should handle env vars fetch failure 1`] = `
+"Prompt: Test Prompt
+
+Full test description
+
+Category: Test
+
+Tags: tag1, tag2
+
+Options: ([*] Required  [ ] Optional)
+  --var1 [*] 
+    test role
+      Not Set (Required)
+  --var2 [ ] 
+    test role 2
+      Not Set
+"
+`;
diff --git a/src/cli/utils/__tests__/conversation-manager.test.ts b/src/cli/utils/__tests__/conversation-manager.test.ts
new file mode 100644
index 0000000..0411ed8
--- /dev/null
+++ b/src/cli/utils/__tests__/conversation-manager.test.ts
@@ -0,0 +1,94 @@
+import { processPromptContent } from '../../../shared/utils/prompt-processing';
+import { ConversationManager } from '../conversation-manager';
+import { resolveInputs } from '../input-resolver';
+import { getPromptFiles } from '../prompts';
+
+jest.mock('../prompts');
+jest.mock('../input-resolver');
+jest.mock('../../../shared/utils/prompt-processing');
+jest.mock('../errors', () => ({
+    handleError: jest.fn()
+}));
+
+describe('ConversationManagerUtils', () => {
+    let conversationManager: ConversationManager;
+    const mockPromptId = 'test-prompt';
+    beforeEach(() => {
+        conversationManager = new ConversationManager(mockPromptId);
+        jest.clearAllMocks();
+    });
+
+    describe('initializeConversation', () => {
+        it('should successfully initialize conversation with user inputs', async () => {
+            const mockUserInputs = { key: 'value' };
+            const mockResolvedInputs = { key: 'resolved-value' };
+            const mockPromptContent = 'Hello {{key}}';
+            const mockResponse = 'Assistant response';
+            (getPromptFiles as jest.Mock).mockResolvedValue({
+                success: true,
+                data: { promptContent: mockPromptContent }
+            });
+            (resolveInputs as jest.Mock).mockResolvedValue(mockResolvedInputs);
+            (processPromptContent as jest.Mock).mockResolvedValue(mockResponse);
+
+            const result = await conversationManager.initializeConversation(mockUserInputs);
+            expect(result).toEqual({
+                success: true,
+                data: mockResponse
+            });
+            expect(getPromptFiles).toHaveBeenCalledWith(mockPromptId);
+            expect(resolveInputs).toHaveBeenCalledWith(mockUserInputs);
+            expect(processPromptContent).toHaveBeenCalled();
+        });
+
+        it('should handle failed prompt files retrieval', async () => {
+            (getPromptFiles as jest.Mock).mockResolvedValue({
+                success: false,
+                error: 'Failed to get prompts'
+            });
+
+            const result = await conversationManager.initializeConversation({});
+            expect(result).toEqual({
+                success: false,
+                error: 'Failed to get prompts'
+            });
+        });
+
+        it('should handle errors during initialization', async () => {
+            const mockError = new Error('Test error');
+            (getPromptFiles as jest.Mock).mockRejectedValue(mockError);
+
+            const result = await conversationManager.initializeConversation({});
+            expect(result).toEqual({
+                success: false,
+                error: 'Failed to initialize conversation'
+            });
+        });
+    });
+
+    describe('continueConversation', () => {
+        it('should successfully continue conversation', async () => {
+            const mockUserInput = 'Hello';
+            const mockResponse = 'Assistant response';
+            (processPromptContent as jest.Mock).mockResolvedValue(mockResponse);
+
+            const result = await conversationManager.continueConversation(mockUserInput);
+            expect(result).toEqual({
+                success: true,
+                data: mockResponse
+            });
+            expect(processPromptContent).toHaveBeenCalled();
+        });
+
+        it('should handle errors during conversation continuation', async () => {
+            const mockError = new Error('Test error');
+            (processPromptContent as jest.Mock).mockRejectedValue(mockError);
+
+            const result = await conversationManager.continueConversation('test');
+            expect(result).toEqual({
+                success: false,
+                error: 'Failed to continue conversation'
+            });
+        });
+    });
+});
diff --git a/src/cli/utils/__tests__/database.test.ts b/src/cli/utils/__tests__/database.test.ts
new file mode 100644
index 0000000..2e39ee7
--- /dev/null
+++ b/src/cli/utils/__tests__/database.test.ts
@@ -0,0 +1,564 @@
+import path from 'path';
+
+import { jest } from '@jest/globals';
+import fs from 'fs-extra';
+import yaml from 'js-yaml';
+import NodeCache from 'node-cache';
+import sqlite3, { RunResult } from 'sqlite3';
+
+import { PromptMetadata } from '../../../shared/types';
+import { fileExists, readDirectory, readFileContent } from '../../../shared/utils/file-system';
+import { cliConfig } from '../../config/cli-config';
+import {
+    runAsync,
+    getAsync,
+    allAsync,
+    handleApiResult,
+    getCachedOrFetch,
+    initDatabase,
+    fetchCategories,
+    getPromptDetails,
+    updatePromptVariable,
+    syncPromptsWithDatabase,
+    cleanupOrphanedData,
+    flushData,
+    db
+} from '../database';
+import { createPrompt } from '../prompts';
+
+jest.mock('fs-extra');
+jest.mock('js-yaml');
+jest.mock('node-cache');
+jest.mock('sqlite3');
+jest.mock('../errors');
+jest.mock('../prompts');
+jest.mock('../../../shared/utils/file-system');
+jest.mock('../../../shared/utils/logger');
+
+const mockFs = fs as jest.Mocked<typeof fs>;
+const mockYaml = yaml as jest.Mocked<typeof yaml>;
+const mockCreatePrompt = createPrompt as jest.MockedFunction<typeof createPrompt>;
+const mockFileExists = fileExists as jest.MockedFunction<typeof fileExists>;
+const mockReadDirectory = readDirectory as jest.MockedFunction<typeof readDirectory>;
+const mockReadFileContent = readFileContent as jest.MockedFunction<typeof readFileContent>;
+describe('DatabaseUtils', () => {
+    let runSpy: jest.SpiedFunction<typeof db.run>;
+    let getSpy: jest.SpiedFunction<typeof db.get>;
+    let allSpy: jest.SpiedFunction<typeof db.all>;
+    beforeEach(() => {
+        jest.clearAllMocks();
+
+        runSpy = jest.spyOn(db, 'run').mockImplementation(function (
+            this: sqlite3.Database,
+            sql: string,
+            paramsOrCallback?: any[] | ((this: RunResult, err: Error | null) => void),
+            callback?: (this: RunResult, err: Error | null) => void
+        ): sqlite3.Database {
+            if (typeof paramsOrCallback === 'function') {
+                callback = paramsOrCallback;
+            }
+
+            if (callback) {
+                callback.call({ lastID: 1, changes: 1 } as RunResult, null);
+            }
+            return this;
+        });
+
+        getSpy = jest.spyOn(db, 'get').mockImplementation(function (
+            this: sqlite3.Database,
+            sql: string,
+            paramsOrCallback?: any[] | ((err: Error | null, row?: any) => void),
+            callback?: (err: Error | null, row?: any) => void
+        ): sqlite3.Database {
+            if (typeof paramsOrCallback === 'function') {
+                callback = paramsOrCallback;
+            }
+
+            if (callback) {
+                callback(null, { id: 1, name: 'Test' });
+            }
+            return this;
+        });
+
+        allSpy = jest.spyOn(db, 'all').mockImplementation(function (
+            this: sqlite3.Database,
+            sql: string,
+            paramsOrCallback?: any[] | ((err: Error | null, rows?: any[]) => void),
+            callback?: (err: Error | null, rows?: any[]) => void
+        ): sqlite3.Database {
+            if (typeof paramsOrCallback === 'function') {
+                callback = paramsOrCallback;
+            }
+
+            if (callback) {
+                callback(null, [{ id: 1 }, { id: 2 }]);
+            }
+            return this;
+        });
+    });
+
+    describe('runAsync', () => {
+        it('should execute SQL run command successfully', async () => {
+            const result = await runAsync('INSERT INTO test_table VALUES (?)', ['test']);
+            expect(result.success).toBe(true);
+            expect(result.data).toEqual({ lastID: 1, changes: 1 });
+        });
+
+        it('should handle SQL run command error', async () => {
+            runSpy.mockImplementation(function (
+                this: sqlite3.Database,
+                sql: string,
+                paramsOrCallback?: any[] | ((this: RunResult, err: Error | null) => void),
+                callback?: (this: RunResult, err: Error | null) => void
+            ): sqlite3.Database {
+                if (typeof paramsOrCallback === 'function') {
+                    callback = paramsOrCallback;
+                }
+
+                if (callback) {
+                    callback.call({} as RunResult, new Error('SQL error'));
+                }
+                return this;
+            });
+
+            const result = await runAsync('INVALID SQL', []);
+            expect(result.success).toBe(false);
+            expect(result.error).toBe('SQL error');
+        });
+    });
+
+    describe('getAsync', () => {
+        it('should execute SQL get command successfully', async () => {
+            const result = await getAsync<{ id: number; name: string }>('SELECT * FROM test_table WHERE id = ?', [1]);
+            expect(result.success).toBe(true);
+            expect(result.data).toEqual({ id: 1, name: 'Test' });
+        });
+
+        it('should handle SQL get command error', async () => {
+            getSpy.mockImplementation(function (
+                this: sqlite3.Database,
+                sql: string,
+                paramsOrCallback?: any[] | ((err: Error | null, row?: any) => void),
+                callback?: (err: Error | null, row?: any) => void
+            ): sqlite3.Database {
+                if (typeof paramsOrCallback === 'function') {
+                    callback = paramsOrCallback;
+                }
+
+                if (callback) {
+                    callback(new Error('SQL error'), undefined);
+                }
+                return this;
+            });
+
+            const result = await getAsync('INVALID SQL', []);
+            expect(result.success).toBe(false);
+            expect(result.error).toBe('SQL error');
+        });
+    });
+
+    describe('allAsync', () => {
+        it('should execute SQL all command successfully', async () => {
+            const result = await allAsync<{ id: number }>('SELECT * FROM test_table', []);
+            expect(result.success).toBe(true);
+            expect(result.data).toEqual([{ id: 1 }, { id: 2 }]);
+        });
+
+        it('should handle SQL all command error', async () => {
+            allSpy.mockImplementation(function (
+                this: sqlite3.Database,
+                sql: string,
+                paramsOrCallback?: any[] | ((err: Error | null, rows?: any[]) => void),
+                callback?: (err: Error | null, rows?: any[]) => void
+            ): sqlite3.Database {
+                if (typeof paramsOrCallback === 'function') {
+                    callback = paramsOrCallback;
+                }
+
+                if (callback) {
+                    callback(new Error('SQL error'), undefined);
+                }
+                return this;
+            });
+
+            const result = await allAsync('INVALID SQL', []);
+            expect(result.success).toBe(false);
+            expect(result.error).toBe('SQL error');
+        });
+    });
+
+    describe('handleApiResult', () => {
+        it('should return data if result is successful', async () => {
+            const result = await handleApiResult({ success: true, data: 'Test Data' }, 'Test Message');
+            expect(result).toBe('Test Data');
+        });
+
+        it('should handle error if result is not successful', async () => {
+            const result = await handleApiResult({ success: false, error: 'Test Error' }, 'Test Message');
+            expect(result).toBeNull();
+        });
+    });
+
+    describe('getCachedOrFetch', () => {
+        let cacheInstance: NodeCache;
+        let cacheGetSpy: jest.SpiedFunction<typeof cacheInstance.get>;
+        let cacheSetSpy: jest.SpiedFunction<typeof cacheInstance.set>;
+        beforeEach(() => {
+            cacheInstance = new NodeCache();
+            cacheGetSpy = jest.spyOn(cacheInstance, 'get');
+            cacheSetSpy = jest.spyOn(cacheInstance, 'set');
+        });
+
+        afterEach(() => {
+            cacheInstance.flushAll();
+            jest.clearAllMocks();
+        });
+
+        it('should return cached data if available', async () => {
+            cacheGetSpy.mockReturnValue('Cached Data');
+
+            const fetchFn = jest.fn(() => Promise.resolve({ success: true, data: 'Fetched Data' }));
+            const result = await getCachedOrFetch('testKey', fetchFn, cacheInstance);
+            expect(result.success).toBe(true);
+            expect(result.data).toBe('Cached Data');
+            expect(fetchFn).not.toHaveBeenCalled();
+        });
+
+        it('should fetch data if not in cache and cache it', async () => {
+            cacheGetSpy.mockReturnValue(undefined);
+
+            const fetchFn = jest.fn(() => Promise.resolve({ success: true, data: 'Fetched Data' }));
+            const result = await getCachedOrFetch('testKey', fetchFn, cacheInstance);
+            expect(result.success).toBe(true);
+            expect(result.data).toBe('Fetched Data');
+            expect(fetchFn).toHaveBeenCalled();
+            expect(cacheSetSpy).toHaveBeenCalledWith('testKey', 'Fetched Data');
+        });
+
+        it('should handle fetch error', async () => {
+            cacheGetSpy.mockReturnValue(undefined);
+
+            const fetchFn = jest.fn(() => Promise.resolve({ success: false, error: 'Fetch Error' }));
+            const result = await getCachedOrFetch('testKey', fetchFn, cacheInstance);
+            expect(result.success).toBe(false);
+            expect(result.error).toBe('Fetch Error');
+            expect(fetchFn).toHaveBeenCalled();
+            expect(cacheSetSpy).not.toHaveBeenCalled();
+        });
+    });
+
+    describe('initDatabase', () => {
+        it('should initialize the database successfully', async () => {
+            mockFs.ensureDir.mockImplementation(() => Promise.resolve());
+
+            const result = await initDatabase();
+            expect(result.success).toBe(true);
+            expect(mockFs.ensureDir).toHaveBeenCalledWith(path.dirname(cliConfig.DB_PATH));
+            expect(runSpy).toHaveBeenCalledTimes(5);
+        });
+
+        it('should handle errors during database initialization', async () => {
+            mockFs.ensureDir.mockImplementation(() => Promise.reject(new Error('FS Error')));
+
+            const result = await initDatabase();
+            expect(result.success).toBe(false);
+            expect(result.error).toBe('Failed to initialize database');
+        });
+    });
+
+    describe('fetchCategories', () => {
+        it('should fetch categories successfully', async () => {
+            const mockData = [
+                {
+                    id: 1,
+                    title: 'Test Prompt',
+                    primary_category: 'Category1',
+                    description: 'Test Description',
+                    path: '/test/path',
+                    tags: 'tag1,tag2',
+                    subcategories: 'sub1,sub2'
+                }
+            ];
+            allSpy.mockImplementationOnce(function (
+                this: sqlite3.Database,
+                sql: string,
+                paramsOrCallback?: any[] | ((err: Error | null, rows?: any[]) => void),
+                callback?: (err: Error | null, rows?: any[]) => void
+            ): sqlite3.Database {
+                if (typeof paramsOrCallback === 'function') {
+                    callback = paramsOrCallback;
+                }
+
+                if (callback) {
+                    callback(null, mockData);
+                }
+                return this;
+            });
+
+            const result = await fetchCategories();
+            expect(result.success).toBe(true);
+            expect(result.data).toEqual({
+                Category1: [
+                    {
+                        id: 1,
+                        title: 'Test Prompt',
+                        primary_category: 'Category1',
+                        description: 'Test Description',
+                        path: '/test/path',
+                        tags: ['tag1', 'tag2'],
+                        subcategories: ['sub1', 'sub2']
+                    }
+                ]
+            });
+        });
+
+        it('should handle errors when fetching categories', async () => {
+            allSpy.mockImplementationOnce(function (
+                this: sqlite3.Database,
+                sql: string,
+                paramsOrCallback?: any[] | ((err: Error | null, rows?: any[]) => void),
+                callback?: (err: Error | null, rows?: any[]) => void
+            ): sqlite3.Database {
+                if (typeof paramsOrCallback === 'function') {
+                    callback = paramsOrCallback;
+                }
+
+                if (callback) {
+                    callback(new Error('DB Error'), undefined);
+                }
+                return this;
+            });
+
+            const result = await fetchCategories();
+            expect(result.success).toBe(false);
+            expect(result.error).toBe('Failed to fetch prompts with categories');
+        });
+    });
+
+    describe('getPromptDetails', () => {
+        it('should get prompt details successfully', async () => {
+            getSpy.mockImplementationOnce(function (
+                this: sqlite3.Database,
+                sql: string,
+                paramsOrCallback?: any[] | ((err: Error | null, row?: any) => void),
+                callback?: (err: Error | null, row?: any) => void
+            ): sqlite3.Database {
+                if (typeof paramsOrCallback === 'function') {
+                    callback = paramsOrCallback;
+                }
+
+                if (callback) {
+                    callback(null, {
+                        id: 1,
+                        title: 'Test Prompt',
+                        content: 'Test Content',
+                        tags: ['tag1', 'tag2']
+                    });
+                }
+                return this;
+            });
+
+            allSpy.mockImplementationOnce(function (
+                this: sqlite3.Database,
+                sql: string,
+                paramsOrCallback?: any[] | ((err: Error | null, rows?: any[]) => void),
+                callback?: (err: Error | null, rows?: any[]) => void
+            ): sqlite3.Database {
+                if (typeof paramsOrCallback === 'function') {
+                    callback = paramsOrCallback;
+                }
+
+                if (callback) {
+                    callback(null, [{ name: 'var1', role: 'user', value: '', optional_for_user: false }]);
+                }
+                return this;
+            });
+
+            const result = await getPromptDetails('1');
+            expect(result.success).toBe(true);
+            expect(result.data).toEqual({
+                id: 1,
+                title: 'Test Prompt',
+                content: 'Test Content',
+                tags: ['tag1', 'tag2'],
+                variables: [
+                    {
+                        name: 'var1',
+                        role: 'user',
+                        value: '',
+                        optional_for_user: false
+                    }
+                ]
+            });
+        });
+
+        it('should handle errors when getting prompt details', async () => {
+            getSpy.mockImplementationOnce(function (
+                this: sqlite3.Database,
+                sql: string,
+                paramsOrCallback?: any[] | ((err: Error | null, row?: any) => void),
+                callback?: (err: Error | null, row?: any) => void
+            ): sqlite3.Database {
+                if (typeof paramsOrCallback === 'function') {
+                    callback = paramsOrCallback;
+                }
+
+                if (callback) {
+                    callback(new Error('DB Error'), undefined);
+                }
+                return this;
+            });
+
+            const result = await getPromptDetails('1');
+            expect(result.success).toBe(false);
+            expect(result.error).toBe('Failed to fetch prompt details');
+        });
+    });
+
+    describe('updatePromptVariable', () => {
+        it('should update prompt variable successfully', async () => {
+            runSpy.mockImplementationOnce(function (
+                this: sqlite3.Database,
+                sql: string,
+                paramsOrCallback?: any[] | ((this: RunResult, err: Error | null) => void),
+                callback?: (this: RunResult, err: Error | null) => void
+            ): sqlite3.Database {
+                if (typeof paramsOrCallback === 'function') {
+                    callback = paramsOrCallback;
+                }
+
+                if (callback) {
+                    callback.call({ changes: 1 } as RunResult, null);
+                }
+                return this;
+            });
+
+            const result = await updatePromptVariable('1', 'var1', 'newValue');
+            expect(result.success).toBe(true);
+        });
+
+        it('should handle errors when updating prompt variable', async () => {
+            runSpy.mockImplementationOnce(function (
+                this: sqlite3.Database,
+                sql: string,
+                paramsOrCallback?: any[] | ((this: RunResult, err: Error | null) => void),
+                callback?: (this: RunResult, err: Error | null) => void
+            ): sqlite3.Database {
+                if (typeof paramsOrCallback === 'function') {
+                    callback = paramsOrCallback;
+                }
+
+                if (callback) {
+                    callback.call({ changes: 0 } as RunResult, null);
+                }
+                return this;
+            });
+
+            const result = await updatePromptVariable('1', 'var1', 'newValue');
+            expect(result.success).toBe(false);
+            expect(result.error).toBe('No variable found with name var1 for prompt 1');
+        });
+    });
+
+    describe('syncPromptsWithDatabase', () => {
+        it('should sync prompts with database successfully', async () => {
+            mockReadDirectory.mockResolvedValue(['prompt1', 'prompt2']);
+            mockFileExists.mockResolvedValue(true);
+            mockReadFileContent.mockResolvedValue('content');
+            mockYaml.load.mockReturnValue({
+                title: 'Test Prompt',
+                primary_category: 'Category1'
+            } as PromptMetadata);
+
+            mockCreatePrompt.mockResolvedValue({ success: true });
+
+            const result = await syncPromptsWithDatabase();
+            expect(result.success).toBe(true);
+            expect(runSpy).toHaveBeenNthCalledWith(1, 'DELETE FROM prompts', [], expect.any(Function));
+            expect(runSpy).toHaveBeenNthCalledWith(2, 'DELETE FROM subcategories', [], expect.any(Function));
+            expect(runSpy).toHaveBeenNthCalledWith(3, 'DELETE FROM variables', [], expect.any(Function));
+            expect(runSpy).toHaveBeenNthCalledWith(4, 'DELETE FROM fragments', [], expect.any(Function));
+            expect(mockCreatePrompt).toHaveBeenCalledTimes(2);
+        });
+
+        it('should handle errors during sync', async () => {
+            mockReadDirectory.mockRejectedValue(new Error('FS Error'));
+
+            const result = await syncPromptsWithDatabase();
+            expect(result.success).toBe(false);
+            expect(result.error).toBe('Failed to sync prompts with database');
+        });
+    });
+
+    describe('cleanupOrphanedData', () => {
+        it('should clean up orphaned data successfully', async () => {
+            mockReadDirectory.mockResolvedValue(['1', '2']);
+
+            allSpy.mockImplementationOnce(function (
+                this: sqlite3.Database,
+                sql: string,
+                paramsOrCallback?: any[] | ((err: Error | null, rows?: any[]) => void),
+                callback?: (err: Error | null, rows?: any[]) => void
+            ): sqlite3.Database {
+                if (typeof paramsOrCallback === 'function') {
+                    callback = paramsOrCallback;
+                }
+
+                if (callback) {
+                    callback(null, []);
+                }
+                return this;
+            });
+
+            const result = await cleanupOrphanedData();
+            expect(result.success).toBe(true);
+            expect(runSpy).toHaveBeenNthCalledWith(
+                1,
+                'DELETE FROM prompts WHERE id NOT IN (?)',
+                ['1,2'],
+                expect.any(Function)
+            );
+            expect(runSpy).toHaveBeenNthCalledWith(
+                2,
+                'DELETE FROM subcategories WHERE prompt_id NOT IN (SELECT id FROM prompts)',
+                [],
+                expect.any(Function)
+            );
+            expect(runSpy).toHaveBeenNthCalledWith(
+                3,
+                'DELETE FROM fragments WHERE prompt_id NOT IN (SELECT id FROM prompts)',
+                [],
+                expect.any(Function)
+            );
+        });
+
+        it('should handle errors during cleanup', async () => {
+            mockReadDirectory.mockRejectedValue(new Error('FS Error'));
+
+            const result = await cleanupOrphanedData();
+            expect(result.success).toBe(false);
+            expect(result.error).toBe('Failed to clean up orphaned data');
+        });
+    });
+
+    describe('flushData', () => {
+        it('should flush data successfully', async () => {
+            mockFs.emptyDir.mockImplementation(() => Promise.resolve());
+
+            await flushData();
+
+            expect(runSpy).toHaveBeenNthCalledWith(1, 'DELETE FROM prompts', [], expect.any(Function));
+            expect(runSpy).toHaveBeenNthCalledWith(2, 'DELETE FROM subcategories', [], expect.any(Function));
+            expect(runSpy).toHaveBeenNthCalledWith(3, 'DELETE FROM variables', [], expect.any(Function));
+            expect(runSpy).toHaveBeenNthCalledWith(4, 'DELETE FROM fragments', [], expect.any(Function));
+            expect(runSpy).toHaveBeenNthCalledWith(5, 'DELETE FROM env_vars', [], expect.any(Function));
+            expect(mockFs.emptyDir).toHaveBeenCalledWith(cliConfig.PROMPTS_DIR);
+        });
+
+        it('should handle errors during data flush', async () => {
+            mockFs.emptyDir.mockImplementation(() => Promise.reject(new Error('FS Error')));
+
+            await expect(flushData()).rejects.toThrow('Failed to flush data');
+        });
+    });
+});
diff --git a/src/cli/utils/__tests__/env-vars.test.ts b/src/cli/utils/__tests__/env-vars.test.ts
new file mode 100644
index 0000000..9d2ef18
--- /dev/null
+++ b/src/cli/utils/__tests__/env-vars.test.ts
@@ -0,0 +1,178 @@
+import { EnvVar } from '../../../shared/types';
+import { runAsync, allAsync } from '../database';
+import { createEnvVar, readEnvVars, updateEnvVar, deleteEnvVar } from '../env-vars';
+
+jest.mock('../database', () => ({
+    runAsync: jest.fn(),
+    allAsync: jest.fn()
+}));
+
+describe('EnvVarsUtils', () => {
+    beforeEach(() => {
+        jest.clearAllMocks();
+        jest.spyOn(console, 'log').mockImplementation(() => {});
+        jest.spyOn(console, 'error').mockImplementation(() => {});
+    });
+
+    describe('createEnvVar', () => {
+        it('should successfully create an environment variable', async () => {
+            const mockEnvVar: Omit<EnvVar, 'id'> = {
+                name: 'TEST_VAR',
+                value: 'test-value',
+                scope: 'global',
+                prompt_id: undefined
+            };
+            (runAsync as jest.Mock).mockResolvedValue({
+                success: true,
+                data: { lastID: 1 }
+            });
+
+            const result = await createEnvVar(mockEnvVar);
+            expect(result).toEqual({
+                success: true,
+                data: { ...mockEnvVar, id: 1 }
+            });
+            expect(runAsync).toHaveBeenCalledWith(
+                'INSERT INTO env_vars (name, value, scope, prompt_id) VALUES (?, ?, ?, ?)',
+                ['TEST_VAR', 'test-value', 'global', null]
+            );
+        });
+
+        it('should handle database errors during creation', async () => {
+            const mockEnvVar: Omit<EnvVar, 'id'> = {
+                name: 'TEST_VAR',
+                value: 'test-value',
+                scope: 'global',
+                prompt_id: undefined
+            };
+            (runAsync as jest.Mock).mockRejectedValue(new Error('Database error'));
+
+            const result = await createEnvVar(mockEnvVar);
+            expect(result).toEqual({
+                success: false,
+                error: 'Failed to create environment variable'
+            });
+        });
+    });
+
+    describe('readEnvVars', () => {
+        it('should read all global environment variables', async () => {
+            const mockEnvVars = [
+                { id: 1, name: 'TEST_VAR1', value: 'value1', scope: 'global', prompt_id: null },
+                { id: 2, name: 'TEST_VAR2', value: 'value2', scope: 'global', prompt_id: null }
+            ];
+            (allAsync as jest.Mock).mockResolvedValue({
+                success: true,
+                data: mockEnvVars
+            });
+
+            const result = await readEnvVars();
+            expect(result).toEqual({
+                success: true,
+                data: mockEnvVars
+            });
+            expect(allAsync).toHaveBeenCalledWith('SELECT * FROM env_vars WHERE scope = "global"', []);
+        });
+
+        it('should read environment variables for specific prompt', async () => {
+            const promptId = 123;
+            const mockEnvVars = [{ id: 1, name: 'TEST_VAR1', value: 'value1', scope: 'prompt', prompt_id: promptId }];
+            (allAsync as jest.Mock).mockResolvedValue({
+                success: true,
+                data: mockEnvVars
+            });
+
+            const result = await readEnvVars(promptId);
+            expect(result).toEqual({
+                success: true,
+                data: mockEnvVars
+            });
+            expect(allAsync).toHaveBeenCalledWith(
+                'SELECT * FROM env_vars WHERE scope = "global" OR (scope = "prompt" AND prompt_id = ?)',
+                [promptId]
+            );
+        });
+
+        it('should handle database errors during read', async () => {
+            (allAsync as jest.Mock).mockRejectedValue(new Error('Database error'));
+
+            const result = await readEnvVars();
+            expect(result).toEqual({
+                success: false,
+                error: 'Failed to read environment variables'
+            });
+        });
+
+        it('should handle unsuccessful database response', async () => {
+            (allAsync as jest.Mock).mockResolvedValue({
+                success: false,
+                data: undefined,
+                error: undefined
+            });
+
+            const result = await readEnvVars();
+            expect(result).toEqual({
+                success: false,
+                error: 'Failed to fetch environment variables'
+            });
+        });
+    });
+
+    describe('updateEnvVar', () => {
+        it('should successfully update an environment variable', async () => {
+            (runAsync as jest.Mock).mockResolvedValue({
+                success: true,
+                data: { changes: 1 }
+            });
+
+            const result = await updateEnvVar(1, 'new-value');
+            expect(result).toEqual({ success: true });
+            expect(runAsync).toHaveBeenCalledWith('UPDATE env_vars SET value = ? WHERE id = ?', ['new-value', 1]);
+        });
+
+        it('should handle non-existent environment variable', async () => {
+            (runAsync as jest.Mock).mockResolvedValue({
+                success: true,
+                data: { changes: 0 }
+            });
+
+            const result = await updateEnvVar(999, 'new-value');
+            expect(result).toEqual({
+                success: false,
+                error: 'No environment variable found with id 999'
+            });
+        });
+
+        it('should handle database errors during update', async () => {
+            (runAsync as jest.Mock).mockRejectedValue(new Error('Database error'));
+
+            const result = await updateEnvVar(1, 'new-value');
+            expect(result).toEqual({
+                success: false,
+                error: 'Failed to update environment variable'
+            });
+        });
+    });
+
+    describe('deleteEnvVar', () => {
+        it('should successfully delete an environment variable', async () => {
+            (runAsync as jest.Mock).mockResolvedValue({
+                success: true
+            });
+
+            const result = await deleteEnvVar(1);
+            expect(result).toEqual({ success: true });
+            expect(runAsync).toHaveBeenCalledWith('DELETE FROM env_vars WHERE id = ?', [1]);
+        });
+
+        it('should handle database errors during deletion', async () => {
+            (runAsync as jest.Mock).mockRejectedValue(new Error('Database error'));
+
+            const result = await deleteEnvVar(1);
+            expect(result).toEqual({
+                success: false,
+                error: 'Failed to delete environment variable'
+            });
+        });
+    });
+});
diff --git a/src/cli/utils/__tests__/errors.test.ts b/src/cli/utils/__tests__/errors.test.ts
new file mode 100644
index 0000000..99faca4
--- /dev/null
+++ b/src/cli/utils/__tests__/errors.test.ts
@@ -0,0 +1,76 @@
+import chalk from 'chalk';
+
+import logger from '../../../shared/utils/logger';
+import { AppError, handleError } from '../errors';
+
+jest.mock('../../../shared/utils/logger');
+
+describe('ErrorsUtils', () => {
+    beforeEach(() => {
+        jest.clearAllMocks();
+
+        jest.spyOn(console, 'error').mockImplementation(() => {});
+    });
+
+    describe('AppError', () => {
+        it('should create an AppError with code and message', () => {
+            const error = new AppError('TEST_ERROR', 'Test error message');
+            expect(error).toBeInstanceOf(Error);
+            expect(error).toBeInstanceOf(AppError);
+            expect(error.code).toBe('TEST_ERROR');
+            expect(error.message).toBe('Test error message');
+            expect(error.name).toBe('AppError');
+        });
+    });
+
+    describe('handleError', () => {
+        const context = 'test context';
+        it('should handle AppError', () => {
+            const error = new AppError('TEST_ERROR', 'Test error message');
+            handleError(error, context);
+
+            expect(logger.error).toHaveBeenCalledWith('Error in test context:');
+            expect(logger.error).toHaveBeenCalledWith('[TEST_ERROR] Test error message');
+            expect(console.error).toHaveBeenCalledWith(
+                chalk.red('Error in test context: [TEST_ERROR] Test error message')
+            );
+        });
+
+        it('should handle standard Error with stack trace', () => {
+            const error = new Error('Standard error');
+            handleError(error, context);
+
+            expect(logger.error).toHaveBeenCalledWith('Error in test context:');
+            expect(logger.error).toHaveBeenCalledWith(error.message);
+            expect(logger.debug).toHaveBeenCalledWith('Stack trace:', error.stack);
+            expect(console.error).toHaveBeenCalledWith(chalk.red('  Message: Standard error'));
+            expect(console.error).toHaveBeenCalledWith(chalk.yellow('  Stack trace:'));
+        });
+
+        it('should handle string error', () => {
+            const errorMessage = 'String error message';
+            handleError(errorMessage, context);
+
+            expect(logger.error).toHaveBeenCalledWith('Error in test context:');
+            expect(logger.error).toHaveBeenCalledWith(errorMessage);
+            expect(console.error).toHaveBeenCalledWith(chalk.red(`  ${errorMessage}`));
+        });
+
+        it('should handle unknown error type', () => {
+            const error = { custom: 'error' };
+            handleError(error, context);
+
+            expect(logger.error).toHaveBeenCalledWith('Error in test context:');
+            expect(logger.error).toHaveBeenCalledWith(`Unknown error: ${JSON.stringify(error)}`);
+            expect(console.error).toHaveBeenCalledWith(chalk.red(`  Unknown error: ${JSON.stringify(error)}`));
+        });
+
+        it('should always show the report message', () => {
+            handleError('any error', context);
+
+            expect(console.error).toHaveBeenCalledWith(
+                chalk.cyan('\nIf this error persists, please report it to the development team.')
+            );
+        });
+    });
+});
diff --git a/src/cli/utils/__tests__/file-system.test.ts b/src/cli/utils/__tests__/file-system.test.ts
new file mode 100644
index 0000000..e1f7371
--- /dev/null
+++ b/src/cli/utils/__tests__/file-system.test.ts
@@ -0,0 +1,77 @@
+import fs from 'fs-extra';
+
+import { readDirectory } from '../../../shared/utils/file-system';
+import { cliConfig } from '../../config/cli-config';
+import { hasPrompts, hasFragments } from '../file-system';
+
+jest.mock('fs-extra');
+jest.mock('../../../shared/utils/file-system');
+jest.mock('../errors', () => ({
+    handleError: jest.fn()
+}));
+
+describe('FileSystemUtils', () => {
+    beforeEach(() => {
+        jest.clearAllMocks();
+    });
+
+    describe('hasPrompts', () => {
+        it('should return true when prompts directory has contents', async () => {
+            (fs.ensureDir as jest.Mock).mockResolvedValue(undefined);
+            (readDirectory as jest.Mock).mockResolvedValue(['prompt1', 'prompt2']);
+
+            const result = await hasPrompts();
+            expect(result).toBe(true);
+            expect(fs.ensureDir).toHaveBeenCalledWith(cliConfig.PROMPTS_DIR);
+            expect(readDirectory).toHaveBeenCalledWith(cliConfig.PROMPTS_DIR);
+        });
+
+        it('should return false when prompts directory is empty', async () => {
+            (fs.ensureDir as jest.Mock).mockResolvedValue(undefined);
+            (readDirectory as jest.Mock).mockResolvedValue([]);
+
+            const result = await hasPrompts();
+            expect(result).toBe(false);
+            expect(fs.ensureDir).toHaveBeenCalledWith(cliConfig.PROMPTS_DIR);
+            expect(readDirectory).toHaveBeenCalledWith(cliConfig.PROMPTS_DIR);
+        });
+
+        it('should handle errors and return false', async () => {
+            const error = new Error('Test error');
+            (fs.ensureDir as jest.Mock).mockRejectedValue(error);
+
+            const result = await hasPrompts();
+            expect(result).toBe(false);
+        });
+    });
+
+    describe('hasFragments', () => {
+        it('should return true when fragments directory has contents', async () => {
+            (fs.ensureDir as jest.Mock).mockResolvedValue(undefined);
+            (readDirectory as jest.Mock).mockResolvedValue(['fragment1', 'fragment2']);
+
+            const result = await hasFragments();
+            expect(result).toBe(true);
+            expect(fs.ensureDir).toHaveBeenCalledWith(cliConfig.FRAGMENTS_DIR);
+            expect(readDirectory).toHaveBeenCalledWith(cliConfig.FRAGMENTS_DIR);
+        });
+
+        it('should return false when fragments directory is empty', async () => {
+            (fs.ensureDir as jest.Mock).mockResolvedValue(undefined);
+            (readDirectory as jest.Mock).mockResolvedValue([]);
+
+            const result = await hasFragments();
+            expect(result).toBe(false);
+            expect(fs.ensureDir).toHaveBeenCalledWith(cliConfig.FRAGMENTS_DIR);
+            expect(readDirectory).toHaveBeenCalledWith(cliConfig.FRAGMENTS_DIR);
+        });
+
+        it('should handle errors and return false', async () => {
+            const error = new Error('Test error');
+            (fs.ensureDir as jest.Mock).mockRejectedValue(error);
+
+            const result = await hasFragments();
+            expect(result).toBe(false);
+        });
+    });
+});
diff --git a/src/cli/utils/__tests__/fragments.test.ts b/src/cli/utils/__tests__/fragments.test.ts
new file mode 100644
index 0000000..bf151c5
--- /dev/null
+++ b/src/cli/utils/__tests__/fragments.test.ts
@@ -0,0 +1,84 @@
+import path from 'path';
+
+import { jest } from '@jest/globals';
+
+import { Fragment } from '../../../shared/types';
+import { readDirectory, readFileContent } from '../../../shared/utils/file-system';
+import { cliConfig } from '../../config/cli-config';
+import { listFragments, viewFragmentContent } from '../fragments';
+
+jest.mock('../../../shared/utils/file-system');
+jest.mock('../errors', () => ({
+    handleError: jest.fn()
+}));
+
+describe('FragmentsUtils', () => {
+    const mockReadDirectory = readDirectory as jest.MockedFunction<typeof readDirectory>;
+    const mockReadFileContent = readFileContent as jest.MockedFunction<typeof readFileContent>;
+    beforeEach(() => {
+        jest.clearAllMocks();
+    });
+
+    describe('listFragments', () => {
+        it('should successfully list fragments', async () => {
+            mockReadDirectory
+                .mockResolvedValueOnce(['category1', 'category2'])
+                .mockResolvedValueOnce(['fragment1.md', 'fragment2.md'])
+                .mockResolvedValueOnce(['fragment3.md']);
+
+            const expectedFragments: Fragment[] = [
+                { category: 'category1', name: 'fragment1', variable: '' },
+                { category: 'category1', name: 'fragment2', variable: '' },
+                { category: 'category2', name: 'fragment3', variable: '' }
+            ];
+            const result = await listFragments();
+            expect(result.success).toBe(true);
+            expect(result.data).toEqual(expectedFragments);
+            expect(mockReadDirectory).toHaveBeenCalledWith(cliConfig.FRAGMENTS_DIR);
+        });
+
+        it('should handle errors when listing fragments', async () => {
+            mockReadDirectory.mockRejectedValueOnce(new Error('Directory read error'));
+
+            const result = await listFragments();
+            expect(result.success).toBe(false);
+            expect(result.error).toBe('Failed to list fragments');
+        });
+
+        it('should ignore non-markdown files', async () => {
+            mockReadDirectory
+                .mockResolvedValueOnce(['category1'])
+                .mockResolvedValueOnce(['fragment1.md', 'fragment2.txt', 'fragment3.md']);
+
+            const expectedFragments: Fragment[] = [
+                { category: 'category1', name: 'fragment1', variable: '' },
+                { category: 'category1', name: 'fragment3', variable: '' }
+            ];
+            const result = await listFragments();
+            expect(result.success).toBe(true);
+            expect(result.data).toEqual(expectedFragments);
+        });
+    });
+
+    describe('viewFragmentContent', () => {
+        it('should successfully read fragment content', async () => {
+            const mockContent = '# Fragment Content';
+            mockReadFileContent.mockResolvedValueOnce(mockContent);
+
+            const result = await viewFragmentContent('category1', 'fragment1');
+            expect(result.success).toBe(true);
+            expect(result.data).toBe(mockContent);
+            expect(mockReadFileContent).toHaveBeenCalledWith(
+                path.join(cliConfig.FRAGMENTS_DIR, 'category1', 'fragment1.md')
+            );
+        });
+
+        it('should handle errors when reading fragment content', async () => {
+            mockReadFileContent.mockRejectedValueOnce(new Error('File read error'));
+
+            const result = await viewFragmentContent('category1', 'fragment1');
+            expect(result.success).toBe(false);
+            expect(result.error).toBe('Failed to view fragment content');
+        });
+    });
+});
diff --git a/src/cli/utils/__tests__/input-resolver.test.ts b/src/cli/utils/__tests__/input-resolver.test.ts
new file mode 100644
index 0000000..bc26d12
--- /dev/null
+++ b/src/cli/utils/__tests__/input-resolver.test.ts
@@ -0,0 +1,122 @@
+import { jest } from '@jest/globals';
+
+import { EnvVar } from '../../../shared/types';
+import { FRAGMENT_PREFIX, ENV_PREFIX } from '../../constants';
+import { readEnvVars } from '../env-vars';
+import { viewFragmentContent } from '../fragments';
+import { resolveValue, resolveInputs } from '../input-resolver';
+
+jest.mock('../env-vars');
+jest.mock('../fragments');
+jest.mock('../errors', () => ({
+    handleError: jest.fn()
+}));
+
+describe('InputResolverUtils', () => {
+    const mockReadEnvVars = readEnvVars as jest.MockedFunction<typeof readEnvVars>;
+    const mockViewFragmentContent = viewFragmentContent as jest.MockedFunction<typeof viewFragmentContent>;
+    beforeEach(() => {
+        jest.clearAllMocks();
+    });
+
+    describe('resolveValue', () => {
+        const mockEnvVars: EnvVar[] = [
+            { id: 1, name: 'TEST_VAR', value: 'test-value', scope: 'global' },
+            { id: 2, name: 'NESTED_VAR', value: '$env:TEST_VAR', scope: 'global' }
+        ];
+        it('should resolve fragment references', async () => {
+            const fragmentContent = '# Test Fragment Content';
+            mockViewFragmentContent.mockResolvedValueOnce({
+                success: true,
+                data: fragmentContent
+            });
+
+            const result = await resolveValue(`${FRAGMENT_PREFIX}category/fragment`, mockEnvVars);
+            expect(result).toBe(fragmentContent);
+            expect(mockViewFragmentContent).toHaveBeenCalledWith('category', 'fragment');
+        });
+
+        it('should handle failed fragment resolution', async () => {
+            mockViewFragmentContent.mockResolvedValueOnce({
+                success: false,
+                error: 'Fragment not found'
+            });
+
+            const value = `${FRAGMENT_PREFIX}category/nonexistent`;
+            const result = await resolveValue(value, mockEnvVars);
+            expect(result).toBe(value);
+        });
+
+        it('should resolve environment variables', async () => {
+            const result = await resolveValue(`${ENV_PREFIX}TEST_VAR`, mockEnvVars);
+            expect(result).toBe('test-value');
+        });
+
+        it('should handle nested environment variables', async () => {
+            const result = await resolveValue(`${ENV_PREFIX}NESTED_VAR`, mockEnvVars);
+            expect(result).toBe('test-value');
+        });
+
+        it('should handle non-existent environment variables', async () => {
+            const value = `${ENV_PREFIX}NONEXISTENT`;
+            const result = await resolveValue(value, mockEnvVars);
+            expect(result).toBe(value);
+        });
+
+        it('should return plain values unchanged', async () => {
+            const value = 'plain-value';
+            const result = await resolveValue(value, mockEnvVars);
+            expect(result).toBe(value);
+        });
+    });
+
+    describe('resolveInputs', () => {
+        it('should resolve multiple inputs', async () => {
+            const inputs = {
+                fragment: `${FRAGMENT_PREFIX}category/fragment`,
+                env: `${ENV_PREFIX}TEST_VAR`,
+                plain: 'plain-value'
+            };
+            mockReadEnvVars.mockResolvedValueOnce({
+                success: true,
+                data: [{ id: 1, name: 'TEST_VAR', value: 'test-value', scope: 'global' }]
+            });
+
+            mockViewFragmentContent.mockResolvedValueOnce({
+                success: true,
+                data: 'fragment-content'
+            });
+
+            const result = await resolveInputs(inputs);
+            expect(result).toEqual({
+                fragment: 'fragment-content',
+                env: 'test-value',
+                plain: 'plain-value'
+            });
+        });
+
+        it('should handle env vars fetch failure', async () => {
+            mockReadEnvVars.mockResolvedValueOnce({
+                success: false,
+                error: 'Failed to fetch env vars'
+            });
+
+            const inputs = {
+                plain: 'value'
+            };
+            const result = await resolveInputs(inputs);
+            expect(result).toEqual({
+                plain: 'value'
+            });
+        });
+
+        it('should handle resolution errors', async () => {
+            mockReadEnvVars.mockRejectedValueOnce(new Error('Failed to fetch env vars'));
+
+            const inputs = {
+                test: 'value'
+            };
+            await expect(resolveInputs(inputs)).rejects.toThrow();
+        });
+    });
+});
diff --git a/src/cli/utils/__tests__/prompts.test.ts b/src/cli/utils/__tests__/prompts.test.ts
new file mode 100644
index 0000000..26a2ef6
--- /dev/null
+++ b/src/cli/utils/__tests__/prompts.test.ts
@@ -0,0 +1,452 @@
+import { RunResult } from 'sqlite3';
+
+import { PromptMetadata, Variable } from '../../../shared/types';
+import { ENV_PREFIX, FRAGMENT_PREFIX } from '../../constants';
+import { allAsync, getAsync, runAsync } from '../database';
+import { readEnvVars } from '../env-vars';
+import { createPrompt, listPrompts, getPromptFiles, getPromptMetadata, viewPromptDetails } from '../prompts';
+
+jest.mock('../database');
+jest.mock('../env-vars');
+jest.mock('chalk', () => ({
+    cyan: jest.fn((text) => text),
+    green: jest.fn((text) => text),
+    blue: jest.fn((text) => text),
+    magenta: jest.fn((text) => text),
+    yellow: jest.fn((text) => text),
+    red: jest.fn((text) => text)
+}));
+jest.mock('../errors', () => ({
+    handleError: jest.fn()
+}));
+
+const mockMetadata: PromptMetadata = {
+    title: 'Test Prompt',
+    primary_category: 'test',
+    subcategories: ['sub1', 'sub2'],
+    directory: 'test-dir',
+    tags: ['tag1', 'tag2'],
+    one_line_description: 'Test description',
+    description: 'Full test description',
+    variables: [
+        { name: 'var1', role: 'test role', optional_for_user: false },
+        { name: 'var2', role: 'test role 2', optional_for_user: true }
+    ],
+    content_hash: 'test-hash',
+    fragments: [{ category: 'test', name: 'fragment1', variable: '{{var1}}' }]
+};
+describe('PromptsUtils', () => {
+    beforeEach(() => {
+        jest.clearAllMocks();
+
+        jest.spyOn(console, 'log').mockImplementation(() => {});
+        jest.spyOn(console, 'error').mockImplementation(() => {});
+    });
+
+    describe('createPrompt', () => {
+        it('should successfully create a prompt with all metadata', async () => {
+            const mockRunAsync = runAsync as jest.MockedFunction<typeof runAsync>;
+            mockRunAsync.mockResolvedValueOnce({
+                success: true,
+                data: {
+                    lastID: 1,
+                    changes: 1
+                } as unknown as RunResult
+            });
+
+            mockRunAsync.mockResolvedValue({
+                success: true,
+                data: {
+                    lastID: 1,
+                    changes: 1
+                } as unknown as RunResult
+            });
+
+            const result = await createPrompt(mockMetadata, 'Test content');
+            expect(result.success).toBe(true);
+            expect(mockRunAsync).toHaveBeenCalledTimes(6);
+            expect(mockRunAsync).toHaveBeenCalledWith(
+                expect.stringContaining('INSERT INTO prompts'),
+                expect.arrayContaining([mockMetadata.title])
+            );
+        });
+
+        it('should handle database errors gracefully', async () => {
+            const mockRunAsync = runAsync as jest.MockedFunction<typeof runAsync>;
+            mockRunAsync.mockResolvedValueOnce({ success: false, error: 'DB error' });
+
+            const result = await createPrompt(mockMetadata, 'Test content');
+            expect(result.success).toBe(false);
+            expect(result.error).toBe('Failed to insert prompt');
+        });
+
+        it('should handle exceptions during prompt creation', async () => {
+            const mockRunAsync = runAsync as jest.MockedFunction<typeof runAsync>;
+            mockRunAsync.mockRejectedValueOnce(new Error('Database error'));
+
+            const result = await createPrompt(mockMetadata, 'Test content');
+            expect(result.success).toBe(false);
+            expect(result.error).toBe('Failed to create prompt');
+        });
+    });
+
+    describe('listPrompts', () => {
+        it('should return list of prompts successfully', async () => {
+            const mockPrompts = [
+                { id: 1, title: 'Prompt 1', primary_category: 'cat1' },
+                { id: 2, title: 'Prompt 2', primary_category: 'cat2' }
+            ];
+            const mockAllAsync = allAsync as jest.MockedFunction<typeof allAsync>;
+            mockAllAsync.mockResolvedValueOnce({ success: true, data: mockPrompts });
+
+            const result = await listPrompts();
+            expect(result.success).toBe(true);
+            expect(result.data).toEqual(mockPrompts);
+        });
+
+        it('should handle empty results', async () => {
+            const mockAllAsync = allAsync as jest.MockedFunction<typeof allAsync>;
+            mockAllAsync.mockResolvedValueOnce({ success: true, data: [] });
+
+            const result = await listPrompts();
+            expect(result.success).toBe(true);
+            expect(result.data).toEqual([]);
+        });
+
+        it('should handle errors', async () => {
+            const mockAllAsync = allAsync as jest.MockedFunction<typeof allAsync>;
+            mockAllAsync.mockResolvedValueOnce({ success: false, error: 'DB error' });
+
+            const result = await listPrompts();
+            expect(result.success).toBe(false);
+            expect(result.error).toBe('Failed to list prompts');
+        });
+
+        it('should return error when listing prompts fails', async () => {
+            const mockAllAsync = allAsync as jest.MockedFunction<typeof allAsync>;
+            mockAllAsync.mockRejectedValueOnce(new Error('Database error'));
+
+            const result = await listPrompts();
+            expect(result.success).toBe(false);
+            expect(result.error).toBe('Failed to list prompts');
+        });
+    });
+
+    describe('getPromptFiles', () => {
+        it('should return prompt content and metadata', async () => {
+            const mockGetAsync = getAsync as jest.MockedFunction<typeof getAsync>;
+            const mockAllAsync = allAsync as jest.MockedFunction<typeof allAsync>;
+            mockGetAsync.mockResolvedValueOnce({
+                success: true,
+                data: { content: 'Test content' }
+            });
+
+            mockGetAsync.mockResolvedValueOnce({
+                success: true,
+                data: {
+                    id: 1,
+                    title: 'Test Prompt',
+                    primary_category: 'test',
+                    directory: 'test-dir',
+                    one_line_description: 'Test description',
+                    description: 'Full test description',
+                    content_hash: 'test-hash',
+                    tags: 'tag1,tag2'
+                }
+            });
+
+            mockAllAsync.mockResolvedValueOnce({
+                success: true,
+                data: [{ name: 'sub1' }, { name: 'sub2' }]
+            });
+
+            mockAllAsync.mockResolvedValueOnce({
+                success: true,
+                data: [
+                    { name: 'var1', role: 'test role', optional_for_user: false },
+                    { name: 'var2', role: 'test role 2', optional_for_user: true }
+                ]
+            });
+
+            mockAllAsync.mockResolvedValueOnce({
+                success: true,
+                data: [{ category: 'test', name: 'fragment1', variable: 'var1' }]
+            });
+
+            const result = await getPromptFiles('1');
+            expect(result.success).toBe(true);
+            expect(result.data).toHaveProperty('promptContent', 'Test content');
+            expect(result.data).toHaveProperty('metadata');
+        });
+
+        it('should return error when prompt content is not found', async () => {
+            const mockGetAsync = getAsync as jest.MockedFunction<typeof getAsync>;
+            mockGetAsync.mockResolvedValueOnce({
+                success: false,
+                error: 'Content not found'
+            });
+
+            const result = await getPromptFiles('1');
+            expect(result.success).toBe(false);
+            expect(result.error).toBe('Prompt not found');
+        });
+
+        it('should return error when metadata retrieval fails', async () => {
+            const mockGetAsync = getAsync as jest.MockedFunction<typeof getAsync>;
+            mockGetAsync.mockResolvedValueOnce({
+                success: true,
+                data: { content: 'Test content' }
+            });
+
+            mockGetAsync.mockResolvedValueOnce({
+                success: false,
+                error: 'Metadata not found'
+            });
+
+            const result = await getPromptFiles('1');
+            expect(result.success).toBe(false);
+            expect(result.error).toBe('Failed to get prompt metadata');
+        });
+
+        it('should return error when prompt content data is undefined', async () => {
+            const mockGetAsync = getAsync as jest.MockedFunction<typeof getAsync>;
+            mockGetAsync.mockResolvedValueOnce({
+                success: true,
+                data: undefined
+            });
+
+            const result = await getPromptFiles('1');
+            expect(result.success).toBe(false);
+            expect(result.error).toBe('Prompt not found');
+        });
+    });
+
+    describe('getPromptMetadata', () => {
+        it('should return error when prompt metadata is not found', async () => {
+            const mockGetAsync = getAsync as jest.MockedFunction<typeof getAsync>;
+            mockGetAsync.mockResolvedValueOnce({
+                success: false,
+                error: 'Prompt not found'
+            });
+
+            const result = await getPromptMetadata('1');
+            expect(result.success).toBe(false);
+            expect(result.error).toBe('Metadata not found');
+        });
+
+        it('should return error when subcategories retrieval fails', async () => {
+            const mockGetAsync = getAsync as jest.MockedFunction<typeof getAsync>;
+            const mockAllAsync = allAsync as jest.MockedFunction<typeof allAsync>;
+            mockGetAsync.mockResolvedValueOnce({
+                success: true,
+                data: mockMetadata
+            });
+
+            mockAllAsync.mockResolvedValueOnce({
+                success: false,
+                error: 'Failed to get subcategories'
+            });
+
+            const result = await getPromptMetadata('1');
+            expect(result.success).toBe(false);
+            expect(result.error).toBe('Failed to get subcategories');
+        });
+
+        it('should return error when prompt metadata data is undefined', async () => {
+            const mockGetAsync = getAsync as jest.MockedFunction<typeof getAsync>;
+            mockGetAsync.mockResolvedValueOnce({
+                success: true,
+                data: undefined
+            });
+
+            const result = await getPromptMetadata('1');
+            expect(result.success).toBe(false);
+            expect(result.error).toBe('Metadata not found');
+        });
+
+        it('should return error when subcategories data is undefined', async () => {
+            const mockGetAsync = getAsync as jest.MockedFunction<typeof getAsync>;
+            const mockAllAsync = allAsync as jest.MockedFunction<typeof allAsync>;
+            mockGetAsync.mockResolvedValueOnce({
+                success: true,
+                data: mockMetadata
+            });
+
+            mockAllAsync.mockResolvedValueOnce({
+                success: true,
+                data: undefined
+            });
+
+            const result = await getPromptMetadata('1');
+            expect(result.success).toBe(false);
+            expect(result.error).toBe('Failed to get subcategories');
+        });
+
+        it('should return error when variables data is undefined', async () => {
+            const mockGetAsync = getAsync as jest.MockedFunction<typeof getAsync>;
+            const mockAllAsync = allAsync as jest.MockedFunction<typeof allAsync>;
+            mockGetAsync.mockResolvedValueOnce({
+                success: true,
+                data: mockMetadata
+            });
+
+            mockAllAsync.mockResolvedValueOnce({
+                success: true,
+                data: [{ name: 'sub1' }, { name: 'sub2' }]
+            });
+
+            mockAllAsync.mockResolvedValueOnce({
+                success: true,
+                data: undefined
+            });
+
+            const result = await getPromptMetadata('1');
+            expect(result.success).toBe(false);
+            expect(result.error).toBe('Failed to get variables');
+        });
+
+        it('should return error when fragments data is undefined', async () => {
+            const mockGetAsync = getAsync as jest.MockedFunction<typeof getAsync>;
+            const mockAllAsync = allAsync as jest.MockedFunction<typeof allAsync>;
+            mockGetAsync.mockResolvedValueOnce({
+                success: true,
+                data: mockMetadata
+            });
+
+            mockAllAsync.mockResolvedValueOnce({
+                success: true,
+                data: [{ name: 'sub1' }, { name: 'sub2' }]
+            });
+
+            mockAllAsync.mockResolvedValueOnce({
+                success: true,
+                data: [
+                    { name: 'var1', role: 'test role', optional_for_user: false },
+                    { name: 'var2', role: 'test role 2', optional_for_user: true }
+                ]
+            });
+
+            mockAllAsync.mockResolvedValueOnce({
+                success: true,
+                data: undefined
+            });
+
+            const result = await getPromptMetadata('1');
+            expect(result.success).toBe(false);
+            expect(result.error).toBe('Failed to get fragments');
+        });
+    });
+
+    describe('viewPromptDetails', () => {
+        const mockPrompt: PromptMetadata = {
+            id: '1',
+            title: 'Test Prompt',
+            primary_category: 'test',
+            subcategories: ['sub1', 'sub2'],
+            directory: 'test-dir',
+            tags: ['tag1', 'tag2'],
+            one_line_description: 'Test description',
+            description: 'Full test description',
+            variables: [
+                { name: 'var1', role: 'test role', optional_for_user: false },
+                { name: 'var2', role: 'test role 2', optional_for_user: true }
+            ],
+            content_hash: 'test-hash',
+            fragments: [{ category: 'test', name: 'fragment1', variable: 'var1' }]
+        };
+        let consoleOutput: string[];
+        beforeEach(() => {
+            jest.clearAllMocks();
+            consoleOutput = [];
+            jest.spyOn(console, 'log').mockImplementation((...args) => {
+                consoleOutput.push(args.join(' '));
+            });
+        });
+
+        it('should display prompt details correctly', async () => {
+            const mockReadEnvVars = readEnvVars as jest.MockedFunction<typeof readEnvVars>;
+            mockReadEnvVars.mockResolvedValueOnce({
+                success: true,
+                data: [{ id: 1, name: 'var1', value: 'test-value', scope: 'global' }]
+            });
+
+            await viewPromptDetails(mockPrompt);
+
+            expect(consoleOutput.join('\n')).toMatchSnapshot();
+        });
+
+        it('should handle env vars fetch failure', async () => {
+            const mockReadEnvVars = readEnvVars as jest.MockedFunction<typeof readEnvVars>;
+            mockReadEnvVars.mockResolvedValueOnce({ success: false, error: 'Failed to read env vars' });
+
+            await viewPromptDetails(mockPrompt);
+
+            expect(consoleOutput.join('\n')).toMatchSnapshot();
+        });
+
+        it('should display fragment variable correctly', async () => {
+            const mockPromptWithFragment: PromptMetadata & { variables: Variable[] } = {
+                ...mockPrompt,
+                variables: [
+                    {
+                        name: 'var1',
+                        role: 'test role',
+                        optional_for_user: false,
+                        value: `${FRAGMENT_PREFIX}fragmentName`
+                    }
+                ]
+            };
+            await viewPromptDetails(mockPromptWithFragment);
+
+            expect(consoleOutput.join('\n')).toMatchSnapshot();
+        });
+
+        it('should display env variable correctly', async () => {
+            const mockPromptWithEnvVar: PromptMetadata & { variables: Variable[] } = {
+                ...mockPrompt,
+                variables: [
+                    {
+                        name: 'var1',
+                        role: 'test role',
+                        optional_for_user: false,
+                        value: `${ENV_PREFIX}ENV_VAR_NAME`
+                    }
+                ]
+            };
+            const mockReadEnvVars = readEnvVars as jest.MockedFunction<typeof readEnvVars>;
+            mockReadEnvVars.mockResolvedValueOnce({
+                success: true,
+                data: [{ id: 1, name: 'ENV_VAR_NAME', value: 'env-value', scope: 'global' }]
+            });
+
+            await viewPromptDetails(mockPromptWithEnvVar);
+
+            expect(consoleOutput.join('\n')).toMatchSnapshot();
+        });
+
+        it('should display regular variable value correctly', async () => {
+            const mockPromptWithValue: PromptMetadata & { variables: Variable[] } = {
+                ...mockPrompt,
+                variables: [
+                    {
+                        name: 'var1',
+                        role: 'test role',
+                        optional_for_user: false,
+                        value: 'regular value'
+                    }
+                ]
+            };
+            await viewPromptDetails(mockPromptWithValue);
+
+            expect(consoleOutput.join('\n')).toMatchSnapshot();
+        });
+
+        it('should not display variable status when isExecute is true', async () => {
+            await viewPromptDetails(mockPrompt, true);
+
+            const output = consoleOutput.join('\n');
+            expect(output).not.toContain('Not Set');
+            expect(output).not.toContain('Set:');
+        });
+    });
+});
diff --git a/src/cli/utils/conversation_manager.util.ts b/src/cli/utils/conversation-manager.ts
similarity index 92%
rename from src/cli/utils/conversation_manager.util.ts
rename to src/cli/utils/conversation-manager.ts
index 8daaf7d..b62b641 100644
--- a/src/cli/utils/conversation_manager.util.ts
+++ b/src/cli/utils/conversation-manager.ts
@@ -1,8 +1,8 @@
-import { handleError } from './error.util';
-import { resolveInputs } from './input_resolution.util';
-import { getPromptFiles } from './prompt_crud.util';
+import { handleError } from './errors';
+import { resolveInputs } from './input-resolver';
+import { getPromptFiles } from './prompts';
 import { ApiResult } from '../../shared/types';
-import { processPromptContent, updatePromptWithVariables } from '../../shared/utils/prompt_processing.util';
+import { processPromptContent, updatePromptWithVariables } from '../../shared/utils/prompt-processing';
 
 interface ConversationMessage {
     role: 'user' | 'assistant';
diff --git a/src/cli/utils/database.util.ts b/src/cli/utils/database.ts
similarity index 92%
rename from src/cli/utils/database.util.ts
rename to src/cli/utils/database.ts
index 45e2fbf..3c93a40 100644
--- a/src/cli/utils/database.util.ts
+++ b/src/cli/utils/database.ts
@@ -5,16 +5,17 @@ import yaml from 'js-yaml';
 import NodeCache from 'node-cache';
 import sqlite3, { RunResult } from 'sqlite3';
 
-import { AppError, handleError } from './error.util';
-import { createPrompt } from './prompt_crud.util';
-import { commonConfig } from '../../shared/config/common.config';
-import { ApiResult, CategoryItem, Metadata, Prompt, Variable } from '../../shared/types';
-import { fileExists, readDirectory, readFileContent } from '../../shared/utils/file_system.util';
-import logger from '../../shared/utils/logger.util';
-import { cliConfig } from '../cli.config';
+import { AppError, handleError } from './errors';
+import { createPrompt } from './prompts';
+import { commonConfig } from '../../shared/config/common-config';
+import { ApiResult, CategoryItem, PromptMetadata, Variable } from '../../shared/types';
+import { fileExists, readDirectory, readFileContent } from '../../shared/utils/file-system';
+import logger from '../../shared/utils/logger';
+import { cliConfig } from '../config/cli-config';
 
 const db = new sqlite3.Database(cliConfig.DB_PATH);
-const cache = new NodeCache({ stdTTL: 600 });
+
+export const cache = new NodeCache({ stdTTL: 600 });
 
 export async function runAsync(sql: string, params: any[] = []): Promise<ApiResult<RunResult>> {
     return new Promise((resolve) => {
@@ -65,17 +66,21 @@ export async function handleApiResult<T>(result: ApiResult<T>, message: string):
     }
 }
 
-export async function getCachedOrFetch<T>(key: string, fetchFn: () => Promise<ApiResult<T>>): Promise<ApiResult<T>> {
-    const cachedResult = cache.get<T>(key);
+export async function getCachedOrFetch<T>(
+    key: string,
+    fetchFn: () => Promise<ApiResult<T>>,
+    cacheInstance: NodeCache = cache
+): Promise<ApiResult<T>> {
+    const cachedResult = cacheInstance.get<T>(key);
 
-    if (cachedResult) {
+    if (cachedResult !== undefined) {
         return { success: true, data: cachedResult };
     }
 
     const result = await fetchFn();
 
     if (result.success && result.data) {
-        cache.set(key, result.data);
+        cacheInstance.set(key, result.data);
     }
     return result;
 }
@@ -177,8 +182,10 @@ export async function fetchCategories(): Promise<ApiResult<Record<string, Catego
     });
 }
 
-export async function getPromptDetails(promptId: string): Promise<ApiResult<Prompt & { variables: Variable[] }>> {
-    const promptResult = await getAsync<Prompt>('SELECT * FROM prompts WHERE id = ?', [promptId]);
+export async function getPromptDetails(
+    promptId: string
+): Promise<ApiResult<PromptMetadata & { variables: Variable[] }>> {
+    const promptResult = await getAsync<PromptMetadata>('SELECT * FROM prompts WHERE id = ?', [promptId]);
     const variablesResult = await allAsync<Variable>(
         'SELECT name, role, value, optional_for_user FROM variables WHERE prompt_id = ?',
         [promptId]
@@ -189,10 +196,7 @@ export async function getPromptDetails(promptId: string): Promise<ApiResult<Prom
     }
 
     if (promptResult.data) {
-        promptResult.data.tags =
-            typeof promptResult.data.tags === 'string'
-                ? promptResult.data.tags.split(',').map((tag) => tag.trim())
-                : promptResult.data.tags || [];
+        promptResult.data.tags = promptResult.data.tags || [];
     }
     return {
         success: true,
@@ -253,7 +257,7 @@ export async function syncPromptsWithDatabase(): Promise<ApiResult<void>> {
                 const metadataContent = await readFileContent(metadataPath);
 
                 try {
-                    const metadata = yaml.load(metadataContent) as Metadata;
+                    const metadata = yaml.load(metadataContent) as PromptMetadata;
                     await createPrompt(metadata, promptContent);
                     logger.info(`Successfully processed prompt: ${dir}`);
                 } catch (error) {
diff --git a/src/cli/utils/env.util.ts b/src/cli/utils/env-vars.ts
similarity index 96%
rename from src/cli/utils/env.util.ts
rename to src/cli/utils/env-vars.ts
index 3898294..529f2c3 100644
--- a/src/cli/utils/env.util.ts
+++ b/src/cli/utils/env-vars.ts
@@ -1,5 +1,5 @@
-import { runAsync, allAsync } from './database.util';
-import { handleError } from './error.util';
+import { runAsync, allAsync } from './database';
+import { handleError } from './errors';
 import { EnvVar, ApiResult } from '../../shared/types';
 
 export async function createEnvVar(envVar: Omit<EnvVar, 'id'>): Promise<ApiResult<EnvVar>> {
diff --git a/src/cli/utils/error.util.ts b/src/cli/utils/errors.ts
similarity index 96%
rename from src/cli/utils/error.util.ts
rename to src/cli/utils/errors.ts
index c3240d4..f535ad3 100644
--- a/src/cli/utils/error.util.ts
+++ b/src/cli/utils/errors.ts
@@ -1,6 +1,6 @@
 import chalk from 'chalk';
 
-import logger from '../../shared/utils/logger.util';
+import logger from '../../shared/utils/logger';
 
 export class AppError extends Error {
     constructor(
diff --git a/src/cli/utils/file_system.util.ts b/src/cli/utils/file-system.ts
similarity index 82%
rename from src/cli/utils/file_system.util.ts
rename to src/cli/utils/file-system.ts
index 0513eda..c2a6bbe 100644
--- a/src/cli/utils/file_system.util.ts
+++ b/src/cli/utils/file-system.ts
@@ -1,8 +1,8 @@
 import fs from 'fs-extra';
 
-import { handleError } from './error.util';
-import { readDirectory } from '../../shared/utils/file_system.util';
-import { cliConfig } from '../cli.config';
+import { handleError } from './errors';
+import { readDirectory } from '../../shared/utils/file-system';
+import { cliConfig } from '../config/cli-config';
 
 export async function hasPrompts(): Promise<boolean> {
     try {
diff --git a/src/cli/utils/fragment_operations.util.ts b/src/cli/utils/fragments.ts
similarity index 93%
rename from src/cli/utils/fragment_operations.util.ts
rename to src/cli/utils/fragments.ts
index 5b6bdc2..c991278 100644
--- a/src/cli/utils/fragment_operations.util.ts
+++ b/src/cli/utils/fragments.ts
@@ -1,9 +1,9 @@
 import path from 'path';
 
-import { handleError } from './error.util';
+import { handleError } from './errors';
 import { ApiResult, Fragment } from '../../shared/types';
-import { readDirectory, readFileContent } from '../../shared/utils/file_system.util';
-import { cliConfig } from '../cli.config';
+import { readDirectory, readFileContent } from '../../shared/utils/file-system';
+import { cliConfig } from '../config/cli-config';
 
 export async function listFragments(): Promise<ApiResult<Fragment[]>> {
     try {
diff --git a/src/cli/utils/input_resolution.util.ts b/src/cli/utils/input-resolver.ts
similarity index 77%
rename from src/cli/utils/input_resolution.util.ts
rename to src/cli/utils/input-resolver.ts
index f4aeb43..cd881a7 100644
--- a/src/cli/utils/input_resolution.util.ts
+++ b/src/cli/utils/input-resolver.ts
@@ -1,9 +1,9 @@
 import { EnvVar } from '../../shared/types';
-import logger from '../../shared/utils/logger.util';
-import { FRAGMENT_PREFIX, ENV_PREFIX } from '../cli.constants';
-import { readEnvVars } from './env.util';
-import { handleError } from './error.util';
-import { viewFragmentContent } from './fragment_operations.util';
+import logger from '../../shared/utils/logger';
+import { FRAGMENT_PREFIX, ENV_PREFIX } from '../constants';
+import { readEnvVars } from './env-vars';
+import { handleError } from './errors';
+import { viewFragmentContent } from './fragments';
 
 export async function resolveValue(value: string, envVars: EnvVar[]): Promise<string> {
     if (value.startsWith(FRAGMENT_PREFIX)) {
@@ -21,7 +21,12 @@ export async function resolveValue(value: string, envVars: EnvVar[]): Promise<st
         const actualEnvVar = envVars.find((v) => v.name === envVarName);
 
         if (actualEnvVar) {
-            return await resolveValue(actualEnvVar.value, envVars);
+            const envVarValue = actualEnvVar.value;
+
+            if (envVarValue.startsWith('$env:')) {
+                return await resolveValue(`${ENV_PREFIX}${envVarValue.slice(5)}`, envVars);
+            }
+            return envVarValue;
         } else {
             logger.warn(`Env var not found: ${envVarName}`);
             return value;
diff --git a/src/cli/utils/metadata.util.ts b/src/cli/utils/metadata.util.ts
deleted file mode 100644
index f5f1d0d..0000000
--- a/src/cli/utils/metadata.util.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-import { getAsync, allAsync } from './database.util';
-import { handleError } from './error.util';
-import { ApiResult, Fragment, Metadata } from '../../shared/types';
-
-export async function getPromptMetadata(promptId: string): Promise<ApiResult<Metadata>> {
-    try {
-        const promptResult = await getAsync<{
-            id: number;
-            title: string;
-            primary_category: string;
-            directory: string;
-            one_line_description: string;
-            description: string;
-            content_hash: string;
-            tags: string;
-        }>('SELECT * FROM prompts WHERE id = ?', [promptId]);
-
-        if (!promptResult.success || !promptResult.data) {
-            return { success: false, error: 'Prompt not found' };
-        }
-
-        const prompt = promptResult.data;
-        const subcategoriesResult = await allAsync<{ name: string }>(
-            'SELECT name FROM subcategories WHERE prompt_id = ?',
-            [promptId]
-        );
-        const variablesResult = await allAsync<{ name: string; role: string; optional_for_user: boolean }>(
-            'SELECT name, role, optional_for_user FROM variables WHERE prompt_id = ?',
-            [promptId]
-        );
-        const fragmentsResult = await allAsync<Fragment>(
-            'SELECT category, name, variable FROM fragments WHERE prompt_id = ?',
-            [promptId]
-        );
-        const metadata: Metadata = {
-            title: prompt.title,
-            primary_category: prompt.primary_category,
-            subcategories: subcategoriesResult.success ? (subcategoriesResult.data?.map((s) => s.name) ?? []) : [],
-            directory: prompt.directory,
-            tags: prompt.tags ? prompt.tags.split(',') : [],
-            one_line_description: prompt.one_line_description,
-            description: prompt.description,
-            variables: variablesResult.success ? (variablesResult.data ?? []) : [],
-            content_hash: prompt.content_hash,
-            fragments: fragmentsResult.success ? (fragmentsResult.data ?? []) : []
-        };
-        return { success: true, data: metadata };
-    } catch (error) {
-        handleError(error, 'getting prompt metadata');
-        return { success: false, error: 'Failed to get prompt metadata' };
-    }
-}
diff --git a/src/cli/utils/prompt_crud.util.ts b/src/cli/utils/prompt_crud.util.ts
deleted file mode 100644
index 7450745..0000000
--- a/src/cli/utils/prompt_crud.util.ts
+++ /dev/null
@@ -1,93 +0,0 @@
-import { allAsync, getAsync, runAsync } from './database.util';
-import { handleError } from './error.util';
-import { getPromptMetadata } from './metadata.util';
-import { ApiResult, Metadata, Prompt } from '../../shared/types';
-
-export async function createPrompt(metadata: Metadata, content: string): Promise<ApiResult<void>> {
-    try {
-        const result = await runAsync(
-            'INSERT INTO prompts (title, content, primary_category, directory, one_line_description, description, content_hash, tags) VALUES (?, ?, ?, ?, ?, ?, ?, ?)',
-            [
-                metadata.title,
-                content,
-                metadata.primary_category,
-                metadata.directory,
-                metadata.one_line_description,
-                metadata.description,
-                metadata.content_hash,
-                metadata.tags.join(',')
-            ]
-        );
-        const promptId = result.data?.lastID;
-
-        if (!promptId) {
-            return { success: false, error: 'Failed to insert prompt' };
-        }
-
-        for (const subcategory of metadata.subcategories) {
-            await runAsync('INSERT INTO subcategories (prompt_id, name) VALUES (?, ?)', [promptId, subcategory]);
-        }
-
-        for (const variable of metadata.variables) {
-            await runAsync('INSERT INTO variables (prompt_id, name, role, optional_for_user) VALUES (?, ?, ?, ?)', [
-                promptId,
-                variable.name,
-                variable.role,
-                variable.optional_for_user
-            ]);
-        }
-
-        for (const fragment of metadata.fragments || []) {
-            await runAsync('INSERT INTO fragments (prompt_id, category, name, variable) VALUES (?, ?, ?, ?)', [
-                promptId,
-                fragment.category,
-                fragment.name,
-                fragment.variable
-            ]);
-        }
-        return { success: true };
-    } catch (error) {
-        handleError(error, 'creating prompt');
-        return { success: false, error: 'Failed to create prompt' };
-    }
-}
-
-export async function listPrompts(): Promise<ApiResult<Prompt[]>> {
-    try {
-        const prompts = await allAsync<Prompt>('SELECT id, title, primary_category FROM prompts');
-        return { success: true, data: prompts.data ?? [] };
-    } catch (error) {
-        handleError(error, 'listing prompts');
-        return { success: false, error: 'Failed to list prompts' };
-    }
-}
-
-export async function getPromptFiles(
-    promptId: string
-): Promise<ApiResult<{ promptContent: string; metadata: Metadata }>> {
-    try {
-        const promptContentResult = await getAsync<{ content: string }>('SELECT content FROM prompts WHERE id = ?', [
-            promptId
-        ]);
-
-        if (!promptContentResult.success || !promptContentResult.data) {
-            return { success: false, error: 'Prompt not found' };
-        }
-
-        const metadataResult = await getPromptMetadata(promptId);
-
-        if (!metadataResult.success || !metadataResult.data) {
-            return { success: false, error: 'Failed to get prompt metadata' };
-        }
-        return {
-            success: true,
-            data: {
-                promptContent: promptContentResult.data.content,
-                metadata: metadataResult.data
-            }
-        };
-    } catch (error) {
-        handleError(error, 'getting prompt files');
-        return { success: false, error: 'Failed to get prompt files' };
-    }
-}
diff --git a/src/cli/utils/prompt_display.util.ts b/src/cli/utils/prompt_display.util.ts
deleted file mode 100644
index b2a8f77..0000000
--- a/src/cli/utils/prompt_display.util.ts
+++ /dev/null
@@ -1,76 +0,0 @@
-import chalk from 'chalk';
-
-import { Prompt, Variable } from '../../shared/types';
-import { formatTitleCase, formatSnakeCase } from '../../shared/utils/string_formatter.util';
-import { FRAGMENT_PREFIX, ENV_PREFIX } from '../cli.constants';
-import { readEnvVars } from './env.util';
-import { handleError } from './error.util';
-
-export async function viewPromptDetails(details: Prompt & { variables: Variable[] }, isExecute = false): Promise<void> {
-    // console.clear();
-    console.log(chalk.cyan('Prompt:'), details.title);
-    console.log(`\n${details.description || ''}`);
-    console.log(chalk.cyan('\nCategory:'), formatTitleCase(details.primary_category));
-
-    let tags: string[] = [];
-
-    if (typeof details.tags === 'string') {
-        tags = details.tags.split(',').map((tag) => tag.trim());
-    } else if (Array.isArray(details.tags)) {
-        tags = details.tags;
-    }
-
-    console.log(chalk.cyan('\nTags:'), tags.length > 0 ? tags.join(', ') : 'No tags');
-    console.log(chalk.cyan('\nOptions:'), '([*] Required  [ ] Optional)');
-    const maxNameLength = Math.max(...details.variables.map((v) => formatSnakeCase(v.name).length));
-
-    try {
-        const envVarsResult = await readEnvVars();
-        const envVars = envVarsResult.success ? envVarsResult.data || [] : [];
-
-        for (const variable of details.variables) {
-            const paddedName = formatSnakeCase(variable.name).padEnd(maxNameLength);
-            const requiredFlag = variable.optional_for_user ? '[ ]' : '[*]';
-            const matchingEnvVar = envVars.find((v) => v.name === variable.name);
-            let status;
-
-            if (variable.value) {
-                if (variable.value.startsWith(FRAGMENT_PREFIX)) {
-                    status = chalk.blue(variable.value);
-                } else if (variable.value.startsWith(ENV_PREFIX)) {
-                    const envVarName = variable.value.split(ENV_PREFIX)[1];
-                    const envVar = envVars.find((v: { name: string }) => v.name === envVarName);
-                    const envValue = envVar ? envVar.value : 'Not found';
-                    status = chalk.magenta(
-                        `${ENV_PREFIX}${formatSnakeCase(envVarName)} (${envValue.substring(0, 30)}${envValue.length > 30 ? '...' : ''})`
-                    );
-                } else {
-                    status = chalk.green(
-                        `Set: ${variable.value.substring(0, 30)}${variable.value.length > 30 ? '...' : ''}`
-                    );
-                }
-            } else {
-                status = variable.optional_for_user ? chalk.yellow('Not Set') : chalk.red('Not Set (Required)');
-            }
-
-            const hint =
-                !isExecute &&
-                matchingEnvVar &&
-                (!variable.value || (variable.value && !variable.value.startsWith(ENV_PREFIX)))
-                    ? chalk.magenta('(Env variable available)')
-                    : '';
-            console.log(`  ${chalk.green(`--${paddedName}`)} ${requiredFlag} ${hint}`);
-            console.log(`    ${variable.role}`);
-
-            if (!isExecute) {
-                console.log(`      ${status}`);
-            }
-        }
-
-        if (!isExecute) {
-            console.log();
-        }
-    } catch (error) {
-        handleError(error, 'viewing prompt details');
-    }
-}
diff --git a/src/cli/utils/prompts.ts b/src/cli/utils/prompts.ts
new file mode 100644
index 0000000..5c187d5
--- /dev/null
+++ b/src/cli/utils/prompts.ts
@@ -0,0 +1,233 @@
+import chalk from 'chalk';
+
+import { allAsync, getAsync, runAsync } from './database';
+import { handleError } from './errors';
+import { ApiResult, Fragment, PromptMetadata, Variable } from '../../shared/types';
+import { formatSnakeCase, formatTitleCase } from '../../shared/utils/string-formatter';
+import { FRAGMENT_PREFIX, ENV_PREFIX } from '../constants';
+import { readEnvVars } from './env-vars';
+
+export async function createPrompt(promptMetadata: PromptMetadata, content: string): Promise<ApiResult<void>> {
+    try {
+        let tagsString: string;
+
+        if (typeof promptMetadata.tags === 'string') {
+            tagsString = promptMetadata.tags;
+        } else {
+            tagsString = promptMetadata.tags.join(',');
+        }
+
+        const result = await runAsync(
+            'INSERT INTO prompts (title, content, primary_category, directory, one_line_description, description, content_hash, tags) VALUES (?, ?, ?, ?, ?, ?, ?, ?)',
+            [
+                promptMetadata.title,
+                content,
+                promptMetadata.primary_category,
+                promptMetadata.directory,
+                promptMetadata.one_line_description,
+                promptMetadata.description,
+                promptMetadata.content_hash,
+                tagsString
+            ]
+        );
+        const promptId = result.data?.lastID;
+
+        if (!promptId) {
+            return { success: false, error: 'Failed to insert prompt' };
+        }
+
+        for (const subcategory of promptMetadata.subcategories) {
+            await runAsync('INSERT INTO subcategories (prompt_id, name) VALUES (?, ?)', [promptId, subcategory]);
+        }
+
+        for (const variable of promptMetadata.variables) {
+            await runAsync('INSERT INTO variables (prompt_id, name, role, optional_for_user) VALUES (?, ?, ?, ?)', [
+                promptId,
+                variable.name,
+                variable.role,
+                variable.optional_for_user
+            ]);
+        }
+
+        for (const fragment of promptMetadata.fragments || []) {
+            await runAsync('INSERT INTO fragments (prompt_id, category, name) VALUES (?, ?, ?)', [
+                promptId,
+                fragment.category,
+                fragment.name
+            ]);
+        }
+        return { success: true };
+    } catch (error) {
+        handleError(error, 'creating prompt');
+        return { success: false, error: 'Failed to create prompt' };
+    }
+}
+
+export async function listPrompts(): Promise<ApiResult<PromptMetadata[]>> {
+    try {
+        const prompts = await allAsync<PromptMetadata>('SELECT id, title, primary_category FROM prompts');
+
+        if (!prompts.success || !prompts.data) {
+            return { success: false, error: 'Failed to list prompts' };
+        }
+        return { success: true, data: prompts.data };
+    } catch (error) {
+        handleError(error, 'listing prompts');
+        return { success: false, error: 'Failed to list prompts' };
+    }
+}
+
+export async function getPromptFiles(
+    promptId: string
+): Promise<ApiResult<{ promptContent: string; metadata: PromptMetadata }>> {
+    try {
+        const promptContentResult = await getAsync<{ content: string }>('SELECT content FROM prompts WHERE id = ?', [
+            promptId
+        ]);
+
+        if (!promptContentResult.success || !promptContentResult.data) {
+            return { success: false, error: 'Prompt not found' };
+        }
+
+        const metadataResult = await getPromptMetadata(promptId);
+
+        if (!metadataResult.success || !metadataResult.data) {
+            return { success: false, error: 'Failed to get prompt metadata' };
+        }
+        return {
+            success: true,
+            data: {
+                promptContent: promptContentResult.data.content,
+                metadata: metadataResult.data
+            }
+        };
+    } catch (error) {
+        handleError(error, 'getting prompt files');
+        return { success: false, error: 'Failed to get prompt files' };
+    }
+}
+
+export async function getPromptMetadata(promptId: string): Promise<ApiResult<PromptMetadata>> {
+    try {
+        const promptResult = await getAsync<PromptMetadata>('SELECT * FROM prompts WHERE id = ?', [promptId]);
+
+        if (!promptResult.success || !promptResult.data) {
+            return { success: false, error: 'Metadata not found' };
+        }
+
+        const subcategoriesResult = await allAsync<{ name: string }>(
+            'SELECT name FROM subcategories WHERE prompt_id = ?',
+            [promptId]
+        );
+
+        if (!subcategoriesResult.success || !subcategoriesResult.data) {
+            return { success: false, error: 'Failed to get subcategories' };
+        }
+
+        const variablesResult = await allAsync<Variable>(
+            'SELECT name, role, optional_for_user, value FROM variables WHERE prompt_id = ?',
+            [promptId]
+        );
+
+        if (!variablesResult.success || !variablesResult.data) {
+            return { success: false, error: 'Failed to get variables' };
+        }
+
+        const fragmentsResult = await allAsync<Fragment>(
+            'SELECT category, name, variable FROM fragments WHERE prompt_id = ?',
+            [promptId]
+        );
+
+        if (!fragmentsResult.success || !fragmentsResult.data) {
+            return { success: false, error: 'Failed to get fragments' };
+        }
+
+        const promptMetadata: PromptMetadata = {
+            id: promptResult.data.id,
+            title: promptResult.data.title,
+            primary_category: promptResult.data.primary_category,
+            subcategories: subcategoriesResult.data.map((s) => s.name),
+            directory: promptResult.data.directory,
+            tags: promptResult.data.tags,
+            one_line_description: promptResult.data.one_line_description,
+            description: promptResult.data.description,
+            variables: variablesResult.data,
+            content_hash: promptResult.data.content_hash,
+            fragments: fragmentsResult.data
+        };
+        return { success: true, data: promptMetadata };
+    } catch (error) {
+        handleError(error, 'getting prompt metadata');
+        return { success: false, error: 'Failed to get prompt metadata' };
+    }
+}
+
+export async function viewPromptDetails(
+    details: PromptMetadata & { variables: Variable[] },
+    isExecute = false
+): Promise<void> {
+    console.log(chalk.cyan('Prompt:'), details.title);
+    console.log(`\n${details.description || ''}`);
+    console.log(chalk.cyan('\nCategory:'), formatTitleCase(details.primary_category));
+    let tagsArray: string[];
+
+    if (typeof details.tags === 'string') {
+        tagsArray = details.tags.split(',');
+    } else {
+        tagsArray = details.tags;
+    }
+
+    console.log(chalk.cyan('\nTags:'), tagsArray.length > 0 ? tagsArray.join(', ') : 'No tags');
+    console.log(chalk.cyan('\nOptions:'), '([*] Required  [ ] Optional)');
+    const maxNameLength = Math.max(...details.variables.map((v) => formatSnakeCase(v.name).length));
+
+    try {
+        const envVarsResult = await readEnvVars();
+        const envVars = envVarsResult.success ? envVarsResult.data || [] : [];
+
+        for (const variable of details.variables) {
+            const paddedName = formatSnakeCase(variable.name).padEnd(maxNameLength);
+            const requiredFlag = variable.optional_for_user ? '[ ]' : '[*]';
+            const matchingEnvVar = envVars.find((v) => v.name === variable.name);
+            let status;
+
+            if (variable.value) {
+                if (variable.value.startsWith(FRAGMENT_PREFIX)) {
+                    status = chalk.blue(variable.value);
+                } else if (variable.value.startsWith(ENV_PREFIX)) {
+                    const envVarName = variable.value.split(ENV_PREFIX)[1];
+                    const envVar = envVars.find((v: { name: string }) => v.name === envVarName);
+                    const envValue = envVar ? envVar.value : 'Not found';
+                    status = chalk.magenta(
+                        `${ENV_PREFIX}${formatSnakeCase(envVarName)} (${envValue.substring(0, 30)}${envValue.length > 30 ? '...' : ''})`
+                    );
+                } else {
+                    status = chalk.green(
+                        `Set: ${variable.value.substring(0, 30)}${variable.value.length > 30 ? '...' : ''}`
+                    );
+                }
+            } else {
+                status = variable.optional_for_user ? chalk.yellow('Not Set') : chalk.red('Not Set (Required)');
+            }
+
+            const hint =
+                !isExecute &&
+                matchingEnvVar &&
+                (!variable.value || (variable.value && !variable.value.startsWith(ENV_PREFIX)))
+                    ? chalk.magenta('(Env variable available)')
+                    : '';
+            console.log(`  ${chalk.green(`--${paddedName}`)} ${requiredFlag} ${hint}`);
+            console.log(`    ${variable.role}`);
+
+            if (!isExecute) {
+                console.log(`      ${status}`);
+            }
+        }
+
+        if (!isExecute) {
+            console.log();
+        }
+    } catch (error) {
+        handleError(error, 'viewing prompt details');
+    }
+}
diff --git a/src/shared/config/__tests__/config.test.ts b/src/shared/config/__tests__/config.test.ts
new file mode 100644
index 0000000..de0afb2
--- /dev/null
+++ b/src/shared/config/__tests__/config.test.ts
@@ -0,0 +1,199 @@
+/* eslint-disable @typescript-eslint/no-require-imports */
+import * as path from 'path';
+
+describe('Config', () => {
+    let originalEnv: NodeJS.ProcessEnv;
+    beforeAll(() => {
+        originalEnv = { ...process.env };
+    });
+
+    beforeEach(() => {
+        process.env = { ...originalEnv };
+        process.env.CLI_ENV = 'cli';
+
+        jest.resetModules();
+
+        jest.mock('fs', () => ({
+            existsSync: jest.fn(() => false),
+            readFileSync: jest.fn(() => '{}'),
+            writeFileSync: jest.fn(),
+            mkdirSync: jest.fn()
+        }));
+
+        jest.mock('../constants', () => ({
+            get isCliEnvironment(): boolean {
+                return process.env.CLI_ENV === 'cli';
+            },
+            CONFIG_DIR: '/mock/config/dir',
+            CONFIG_FILE: '/mock/config/dir/config.json'
+        }));
+
+        jest.mock('../common-config', () => ({
+            commonConfig: {
+                ANTHROPIC_API_KEY: undefined,
+                ANTHROPIC_MODEL: 'claude-3-5-sonnet-20240620',
+                ANTHROPIC_MAX_TOKENS: 8000,
+                PROMPT_FILE_NAME: 'prompt.md',
+                METADATA_FILE_NAME: 'metadata.yml',
+                LOG_LEVEL: 'info',
+                REMOTE_REPOSITORY: '',
+                CLI_ENV: 'cli'
+            }
+        }));
+
+        jest.mock('../../../cli/config/cli-config', () => {
+            const mockConfigDir = '/mock/config/dir';
+            return {
+                cliConfig: {
+                    PROMPTS_DIR: 'prompts',
+                    FRAGMENTS_DIR: 'fragments',
+                    DB_PATH: path.join(mockConfigDir, 'prompts.sqlite'),
+                    TEMP_DIR: path.join(mockConfigDir, 'temp'),
+                    MENU_PAGE_SIZE: 20
+                }
+            };
+        });
+    });
+
+    afterEach(() => {
+        process.env = { ...originalEnv };
+    });
+
+    describe('getConfig', () => {
+        it('should return default config when no file exists', () => {
+            process.env.CLI_ENV = 'cli';
+
+            const mockFs = require('fs');
+            mockFs.existsSync.mockReturnValue(false);
+            mockFs.readFileSync.mockReturnValue('{}');
+
+            const { getConfig } = require('../../config');
+            const config = getConfig();
+            expect(config.ANTHROPIC_API_KEY).toBeUndefined();
+            expect(config).toMatchObject({
+                ANTHROPIC_MAX_TOKENS: 8000,
+                ANTHROPIC_MODEL: 'claude-3-5-sonnet-20240620',
+                CLI_ENV: 'cli'
+            });
+        });
+
+        it('should merge file config with default config', () => {
+            process.env.CLI_ENV = 'cli';
+
+            const mockFs = require('fs');
+            mockFs.existsSync.mockReturnValue(true);
+            mockFs.readFileSync.mockReturnValue(
+                JSON.stringify({
+                    ANTHROPIC_API_KEY: 'file-key'
+                })
+            );
+
+            const { getConfig } = require('../../config');
+            const config = getConfig();
+            expect(config.ANTHROPIC_API_KEY).toBe('file-key');
+        });
+    });
+
+    describe('getConfigValue', () => {
+        it('should prefer process.env value in non-CLI environment', () => {
+            process.env.CLI_ENV = 'app';
+            process.env.ANTHROPIC_API_KEY = 'env-key';
+
+            const mockFs = require('fs');
+            mockFs.readFileSync.mockReturnValue(
+                JSON.stringify({
+                    ANTHROPIC_API_KEY: 'file-key'
+                })
+            );
+
+            const { getConfigValue, clearConfigCache } = require('../../config');
+            clearConfigCache();
+
+            const value = getConfigValue('ANTHROPIC_API_KEY');
+            expect(value).toBe('env-key');
+        });
+
+        it('should use file value in CLI environment even if env var exists', () => {
+            process.env.CLI_ENV = 'cli';
+            process.env.ANTHROPIC_API_KEY = 'env-key';
+
+            const mockFs = require('fs');
+            mockFs.existsSync.mockReturnValue(true);
+            mockFs.readFileSync.mockReturnValue(
+                JSON.stringify({
+                    ANTHROPIC_API_KEY: 'file-key'
+                })
+            );
+
+            const { getConfigValue, clearConfigCache } = require('../../config');
+            clearConfigCache();
+
+            const value = getConfigValue('ANTHROPIC_API_KEY');
+            expect(value).toBe('file-key');
+        });
+
+        it('should return updated value after setConfig', () => {
+            process.env.CLI_ENV = 'cli';
+
+            const mockFs = require('fs');
+            mockFs.existsSync.mockReturnValue(true);
+            mockFs.readFileSync.mockReturnValue(
+                JSON.stringify({
+                    ANTHROPIC_API_KEY: 'initial-key'
+                })
+            );
+
+            const { setConfig, getConfigValue, clearConfigCache } = require('../../config');
+            clearConfigCache();
+
+            expect(getConfigValue('ANTHROPIC_API_KEY')).toBe('initial-key');
+
+            setConfig('ANTHROPIC_API_KEY', 'updated-key');
+
+            expect(getConfigValue('ANTHROPIC_API_KEY')).toBe('updated-key');
+            expect(process.env.ANTHROPIC_API_KEY).toBe('updated-key');
+        });
+    });
+
+    describe('setConfig', () => {
+        it('should throw error if not in CLI environment', () => {
+            process.env.CLI_ENV = 'app';
+
+            const { setConfig } = require('../../config');
+            expect(() => setConfig('ANTHROPIC_API_KEY', 'new-key')).toThrow();
+        });
+
+        it('should update config file and process.env', () => {
+            process.env.CLI_ENV = 'cli';
+
+            const mockFs = require('fs');
+            mockFs.existsSync.mockReturnValue(true);
+
+            const { setConfig } = require('../../config');
+            setConfig('ANTHROPIC_API_KEY', 'new-key');
+
+            expect(mockFs.writeFileSync).toHaveBeenCalledWith('/mock/config/dir/config.json', expect.any(String));
+            expect(process.env.ANTHROPIC_API_KEY).toBe('new-key');
+        });
+    });
+
+    describe('environment specific behavior', () => {
+        it('should prefer env vars in non-CLI environment', () => {
+            process.env.CLI_ENV = 'app';
+            process.env.ANTHROPIC_API_KEY = 'env-key';
+
+            const mockFs = require('fs');
+            mockFs.readFileSync.mockReturnValue(
+                JSON.stringify({
+                    ANTHROPIC_API_KEY: 'file-key'
+                })
+            );
+
+            const { getConfigValue, clearConfigCache } = require('../../config');
+            clearConfigCache();
+
+            const value = getConfigValue('ANTHROPIC_API_KEY');
+            expect(value).toBe('env-key');
+        });
+    });
+});
diff --git a/src/shared/config/common.config.ts b/src/shared/config/common-config.ts
similarity index 95%
rename from src/shared/config/common.config.ts
rename to src/shared/config/common-config.ts
index 1f868d6..531bd19 100644
--- a/src/shared/config/common.config.ts
+++ b/src/shared/config/common-config.ts
@@ -2,7 +2,6 @@ import dotenv from 'dotenv';
 
 import { Config } from '.';
 
-// Load .env file if running locally
 if (process.env.NODE_ENV !== 'production') {
     dotenv.config();
 }
diff --git a/src/shared/config/config.constants.ts b/src/shared/config/constants.ts
similarity index 69%
rename from src/shared/config/config.constants.ts
rename to src/shared/config/constants.ts
index 1313548..d754ffa 100644
--- a/src/shared/config/config.constants.ts
+++ b/src/shared/config/constants.ts
@@ -1,9 +1,7 @@
 import * as os from 'os';
 import * as path from 'path';
 
-import { commonConfig } from './common.config';
-
-export const isCliEnvironment = commonConfig.CLI_ENV === 'cli';
+export const isCliEnvironment = process.env.CLI_ENV === 'cli';
 
 export const CONFIG_DIR = isCliEnvironment
     ? path.join(os.homedir(), '.prompt-library-cli')
diff --git a/src/shared/config/index.ts b/src/shared/config/index.ts
index 516bcd1..65dd5dd 100644
--- a/src/shared/config/index.ts
+++ b/src/shared/config/index.ts
@@ -1,78 +1,86 @@
 import * as fs from 'fs';
 
-import { CommonConfig, commonConfig } from './common.config';
-import { CONFIG_DIR, CONFIG_FILE, isCliEnvironment } from './config.constants';
-import { AppConfig, appConfig } from '../../app/config/app.config';
-import { CliConfig, cliConfig } from '../../cli/cli.config';
+import { CommonConfig, commonConfig } from './common-config';
+import { CONFIG_DIR, CONFIG_FILE, isCliEnvironment } from './constants';
+import { appConfig, AppConfig } from '../../app/config/app-config';
+import { CliConfig, cliConfig } from '../../cli/config/cli-config';
 
 export type Config = CommonConfig & (CliConfig | AppConfig);
 
 let loadedConfig: Config | null = null;
+let lastCliEnv: string | undefined;
+
+export function clearConfigCache(): void {
+    loadedConfig = null;
+    lastCliEnv = undefined;
+}
 
 function loadConfig(): Config {
-    const environmentConfig = isCliEnvironment ? cliConfig : appConfig;
-    let config: Config = { ...commonConfig, ...environmentConfig };
+    if (process.env.CLI_ENV !== lastCliEnv) {
+        loadedConfig = null;
+        lastCliEnv = process.env.CLI_ENV;
+    }
 
-    if (isCliEnvironment) {
-        if (!fs.existsSync(CONFIG_DIR)) {
-            fs.mkdirSync(CONFIG_DIR, { recursive: true });
-        }
+    if (loadedConfig) {
+        return JSON.parse(JSON.stringify(loadedConfig));
+    }
 
-        if (fs.existsSync(CONFIG_FILE)) {
+    const environmentConfig = isCliEnvironment ? cliConfig : appConfig;
+    let config = {
+        ...commonConfig,
+        ...environmentConfig
+    } as Config;
+
+    if (isCliEnvironment && fs.existsSync(CONFIG_FILE)) {
+        try {
             const fileConfig = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf-8'));
             config = { ...config, ...fileConfig };
+        } catch (error) {
+            console.error('Error loading config file:', error);
         }
     }
+
+    loadedConfig = JSON.parse(JSON.stringify(config));
     return config;
 }
 
+export function getConfig(): Readonly<Config> {
+    return loadConfig();
+}
+
 export function setConfig<K extends keyof Config>(key: K, value: Config[K]): void {
-    if (!isCliEnvironment) {
+    if (process.env.CLI_ENV !== 'cli') {
         throw new Error('setConfig is only available in CLI environment');
     }
 
-    if (!loadedConfig) {
-        loadedConfig = loadConfig();
+    if (!fs.existsSync(CONFIG_DIR)) {
+        fs.mkdirSync(CONFIG_DIR, { recursive: true });
     }
 
-    loadedConfig[key] = value;
+    const config = loadConfig();
+    const updatedConfig = { ...config, [key]: value };
+    fs.writeFileSync(CONFIG_FILE, JSON.stringify(updatedConfig, null, 2));
 
-    // Update process.env to reflect the change
-    if (typeof value === 'string') {
-        process.env[key.toString()] = value;
-    }
-
-    // Write to file
-    fs.writeFileSync(CONFIG_FILE, JSON.stringify(loadedConfig, null, 2));
-
-    // Clear the cache by reassigning loadedConfig to null
-    loadedConfig = null as unknown as Config;
-}
+    loadedConfig = updatedConfig;
 
-export function getConfig(): Readonly<Config> {
-    if (loadedConfig === null) {
-        loadedConfig = loadConfig();
+    if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
+        process.env[key] = String(value);
     }
-    return loadedConfig;
 }
 
 export function getConfigValue<K extends keyof Config>(key: K): Config[K] {
-    if (loadedConfig === null) {
-        loadedConfig = loadConfig();
-    }
+    const config = loadConfig();
 
-    if (isCliEnvironment) {
-        return loadedConfig[key];
-    } else {
-        const envValue = process.env[key.toString()];
-        return (envValue !== undefined ? envValue : loadedConfig[key]) as Config[K];
-    }
-}
-
-type ConfigValue = Config[keyof Config];
+    if (!isCliEnvironment && process.env[key] !== undefined) {
+        const envValue = process.env[key];
+        const currentValue = config[key];
 
-export const config: Readonly<Config> = new Proxy({} as Config, {
-    get(_, prop: string): ConfigValue {
-        return getConfigValue(prop as keyof Config);
+        if (typeof currentValue === 'number') {
+            return Number(envValue) as Config[K];
+        } else if (typeof currentValue === 'boolean') {
+            return (envValue?.toLowerCase() === 'true') as unknown as Config[K];
+        }
+        return envValue as Config[K];
     }
-});
+    return config[key];
+}
diff --git a/src/shared/types/index.ts b/src/shared/types/index.ts
index bdee51e..58ed1bd 100644
--- a/src/shared/types/index.ts
+++ b/src/shared/types/index.ts
@@ -6,15 +6,6 @@ export interface EnvVar {
     prompt_id?: number;
 }
 
-export interface Prompt {
-    id: string;
-    title: string;
-    primary_category: string;
-    description?: string;
-    tags?: string | string[];
-    variables: Variable[];
-}
-
 export interface CategoryItem {
     id: string;
     title: string;
@@ -37,12 +28,13 @@ export type ApiResult<T> = {
     error?: string;
 };
 
-export interface Metadata {
+export interface PromptMetadata {
+    id?: string;
     title: string;
     primary_category: string;
     subcategories: string[];
     directory: string;
-    tags: string[];
+    tags: string | string[];
     one_line_description: string;
     description: string;
     variables: Variable[];
diff --git a/src/shared/utils/__tests__/anthropic-client.test.ts b/src/shared/utils/__tests__/anthropic-client.test.ts
new file mode 100644
index 0000000..dc506f1
--- /dev/null
+++ b/src/shared/utils/__tests__/anthropic-client.test.ts
@@ -0,0 +1,175 @@
+import { Anthropic } from '@anthropic-ai/sdk';
+import { Message, MessageStreamEvent } from '@anthropic-ai/sdk/resources/messages.js';
+
+import { commonConfig } from '../../config/common-config';
+import { sendAnthropicRequestClassic, sendAnthropicRequestStream, validateAnthropicApiKey } from '../anthropic-client';
+
+jest.mock('@anthropic-ai/sdk');
+jest.mock('../../../cli/utils/errors');
+jest.mock('../../config/common-config');
+
+describe('AnthropicClientUtils', () => {
+    const testMessages = [
+        { role: 'user', content: 'Hello' },
+        { role: 'assistant', content: 'Hi there' }
+    ];
+    const mockResponse = {
+        id: 'msg_123',
+        type: 'message',
+        role: 'assistant',
+        content: [{ type: 'text', text: 'Test response' }],
+        model: 'claude-3',
+        stop_reason: null,
+        stop_sequence: null,
+        usage: { input_tokens: 10, output_tokens: 20 }
+    } as Message;
+    beforeEach(() => {
+        jest.clearAllMocks();
+        process.env.ANTHROPIC_API_KEY = 'test-key';
+    });
+
+    afterEach(() => {
+        delete process.env.ANTHROPIC_API_KEY;
+    });
+
+    describe('sendAnthropicRequestClassic', () => {
+        it('should successfully send a classic request', async () => {
+            const mockCreate = jest.fn().mockResolvedValue(mockResponse);
+            const mockMessagesAPI = {
+                create: mockCreate,
+                stream: jest.fn()
+            } as unknown as typeof Anthropic.prototype.messages;
+            (Anthropic as jest.MockedClass<typeof Anthropic>).prototype.messages = mockMessagesAPI;
+
+            const result = await sendAnthropicRequestClassic(testMessages);
+            expect(result).toBe(mockResponse);
+            expect(mockCreate).toHaveBeenCalledWith({
+                model: commonConfig.ANTHROPIC_MODEL,
+                max_tokens: commonConfig.ANTHROPIC_MAX_TOKENS,
+                messages: testMessages.map((msg) => ({
+                    role: msg.role === 'user' ? 'user' : 'assistant',
+                    content: msg.content
+                }))
+            });
+        });
+
+        it('should handle API errors properly', async () => {
+            const mockError = new Error('API Error');
+            const mockCreate = jest.fn().mockRejectedValue(mockError);
+            (Anthropic as jest.MockedClass<typeof Anthropic>).prototype.messages = {
+                create: mockCreate,
+                stream: jest.fn(),
+                _client: {} as any
+            } as any;
+
+            await expect(sendAnthropicRequestClassic(testMessages)).rejects.toThrow(mockError);
+        });
+    });
+
+    describe('sendAnthropicRequestStream', () => {
+        it('should successfully stream responses', async () => {
+            const mockStreamEvents: MessageStreamEvent[] = [
+                {
+                    type: 'message_start',
+                    message: {
+                        id: 'msg_123',
+                        type: 'message',
+                        role: 'assistant',
+                        content: [],
+                        model: 'claude-3',
+                        stop_reason: null,
+                        stop_sequence: null,
+                        usage: { input_tokens: 0, output_tokens: 0 }
+                    }
+                },
+                { type: 'content_block_start', index: 0, content_block: { type: 'text', text: '' } },
+                { type: 'content_block_delta', index: 0, delta: { type: 'text_delta', text: 'Test' } },
+                { type: 'content_block_stop', index: 0 },
+                {
+                    type: 'message_delta',
+                    delta: {
+                        stop_reason: 'end_turn',
+                        stop_sequence: null
+                    },
+                    usage: { output_tokens: 1 }
+                },
+                { type: 'message_stop' }
+            ];
+            const mockStream = {
+                [Symbol.asyncIterator]: async function* (): AsyncIterableIterator<MessageStreamEvent> {
+                    for (const event of mockStreamEvents) {
+                        yield event;
+                    }
+                }
+            };
+            const mockStreamFn = jest.fn().mockReturnValue(mockStream);
+            const mockMessagesAPI = {
+                stream: mockStreamFn,
+                create: jest.fn()
+            } as unknown as typeof Anthropic.prototype.messages;
+            (Anthropic as jest.MockedClass<typeof Anthropic>).prototype.messages = mockMessagesAPI;
+
+            const events: MessageStreamEvent[] = [];
+
+            for await (const event of sendAnthropicRequestStream(testMessages)) {
+                events.push(event);
+            }
+
+            expect(events).toEqual(mockStreamEvents);
+            expect(mockStreamFn).toHaveBeenCalledWith({
+                model: commonConfig.ANTHROPIC_MODEL,
+                max_tokens: commonConfig.ANTHROPIC_MAX_TOKENS,
+                messages: testMessages.map((msg) => ({
+                    role: msg.role === 'user' ? 'user' : 'assistant',
+                    content: msg.content
+                }))
+            });
+        });
+
+        it('should handle streaming errors properly', async () => {
+            const mockError = new Error('Stream Error');
+            const mockStreamFn = jest.fn().mockImplementation(() => {
+                throw mockError;
+            });
+            (Anthropic as jest.MockedClass<typeof Anthropic>).prototype.messages = {
+                stream: mockStreamFn,
+                create: jest.fn(),
+                _client: {} as any
+            } as any;
+
+            const generator = sendAnthropicRequestStream(testMessages);
+            await expect(generator.next()).rejects.toThrow(mockError);
+        });
+    });
+
+    describe('validateAnthropicApiKey', () => {
+        it('should return true for valid API key', async () => {
+            const mockCreate = jest.fn().mockResolvedValue(mockResponse);
+            (Anthropic as jest.MockedClass<typeof Anthropic>).prototype.messages = {
+                create: mockCreate,
+                stream: jest.fn(),
+                _client: {} as any
+            } as any;
+
+            const result = await validateAnthropicApiKey();
+            expect(result).toBe(true);
+            expect(mockCreate).toHaveBeenCalledWith({
+                model: commonConfig.ANTHROPIC_MODEL,
+                max_tokens: commonConfig.ANTHROPIC_MAX_TOKENS,
+                messages: [{ role: 'user', content: 'Test request' }]
+            });
+        });
+
+        it('should return false for invalid API key', async () => {
+            const mockCreate = jest.fn().mockRejectedValue(new Error('Invalid API key'));
+            (Anthropic as jest.MockedClass<typeof Anthropic>).prototype.messages = {
+                create: mockCreate,
+                stream: jest.fn(),
+                _client: {} as any
+            } as any;
+
+            const result = await validateAnthropicApiKey();
+            expect(result).toBe(false);
+        });
+    });
+});
diff --git a/src/shared/utils/__tests__/file-system.test.ts b/src/shared/utils/__tests__/file-system.test.ts
new file mode 100644
index 0000000..8fa1b4a
--- /dev/null
+++ b/src/shared/utils/__tests__/file-system.test.ts
@@ -0,0 +1,224 @@
+import { Dirent, Stats } from 'fs';
+import * as fs from 'fs/promises';
+
+import { jest } from '@jest/globals';
+
+import { handleError } from '../../../cli/utils/errors';
+import {
+    readFileContent,
+    writeFileContent,
+    readDirectory,
+    createDirectory,
+    renameFile,
+    copyFile,
+    removeDirectory,
+    fileExists,
+    isDirectory,
+    isFile
+} from '../file-system';
+
+jest.mock('fs/promises');
+const mockFs = jest.mocked(fs);
+jest.mock('../../../cli/utils/errors');
+const mockHandleError = jest.mocked(handleError);
+describe('FileSystemUtils', () => {
+    beforeEach(() => {
+        jest.clearAllMocks();
+    });
+
+    describe('readFileContent', () => {
+        it('should read file content successfully', async () => {
+            const testContent = 'test content';
+            mockFs.readFile.mockResolvedValue(testContent);
+
+            const result = await readFileContent('test.txt');
+            expect(result).toBe(testContent);
+            expect(mockFs.readFile).toHaveBeenCalledWith('test.txt', 'utf-8');
+        });
+
+        it('should handle errors when reading file', async () => {
+            const error = new Error('Read error');
+            mockFs.readFile.mockRejectedValue(error);
+
+            await expect(readFileContent('test.txt')).rejects.toThrow(error);
+            expect(mockHandleError).toHaveBeenCalledWith(error, 'reading file test.txt');
+        });
+    });
+
+    describe('writeFileContent', () => {
+        it('should write file content successfully', async () => {
+            const testContent = 'test content';
+            mockFs.writeFile.mockResolvedValue();
+
+            await writeFileContent('test.txt', testContent);
+
+            expect(mockFs.writeFile).toHaveBeenCalledWith('test.txt', testContent, 'utf-8');
+        });
+
+        it('should handle errors when writing file', async () => {
+            const error = new Error('Write error');
+            mockFs.writeFile.mockRejectedValue(error);
+
+            await expect(writeFileContent('test.txt', 'content')).rejects.toThrow(error);
+            expect(mockHandleError).toHaveBeenCalledWith(error, 'writing file test.txt');
+        });
+    });
+
+    describe('readDirectory', () => {
+        it('should read directory contents successfully', async () => {
+            const testFiles = ['file1.txt', 'file2.txt'];
+            (mockFs.readdir as jest.MockedFunction<typeof fs.readdir>).mockResolvedValue(
+                testFiles as unknown as Dirent[]
+            );
+
+            const result = await readDirectory('testDir');
+            expect(result).toEqual(testFiles);
+            expect(mockFs.readdir).toHaveBeenCalledWith('testDir', { withFileTypes: false });
+        });
+
+        it('should handle errors when reading directory', async () => {
+            const error = new Error('Read dir error');
+            mockFs.readdir.mockRejectedValue(error);
+
+            await expect(readDirectory('testDir')).rejects.toThrow(error);
+            expect(mockHandleError).toHaveBeenCalledWith(error, 'reading directory testDir');
+        });
+    });
+
+    describe('createDirectory', () => {
+        it('should create directory successfully', async () => {
+            mockFs.mkdir.mockResolvedValue(undefined);
+
+            await createDirectory('testDir');
+
+            expect(mockFs.mkdir).toHaveBeenCalledWith('testDir', { recursive: true });
+        });
+
+        it('should handle errors when creating directory', async () => {
+            const error = new Error('Create dir error');
+            mockFs.mkdir.mockRejectedValue(error);
+
+            await expect(createDirectory('testDir')).rejects.toThrow(error);
+            expect(mockHandleError).toHaveBeenCalledWith(error, 'creating directory testDir');
+        });
+    });
+
+    describe('renameFile', () => {
+        it('should rename file successfully', async () => {
+            mockFs.rename.mockResolvedValue();
+
+            await renameFile('old.txt', 'new.txt');
+
+            expect(mockFs.rename).toHaveBeenCalledWith('old.txt', 'new.txt');
+        });
+
+        it('should handle errors when renaming file', async () => {
+            const error = new Error('Rename error');
+            mockFs.rename.mockRejectedValue(error);
+
+            await expect(renameFile('old.txt', 'new.txt')).rejects.toThrow(error);
+            expect(mockHandleError).toHaveBeenCalledWith(error, 'renaming file from old.txt to new.txt');
+        });
+    });
+
+    describe('copyFile', () => {
+        it('should copy file successfully', async () => {
+            mockFs.copyFile.mockResolvedValue();
+
+            await copyFile('src.txt', 'dst.txt');
+
+            expect(mockFs.copyFile).toHaveBeenCalledWith('src.txt', 'dst.txt');
+        });
+
+        it('should handle errors when copying file', async () => {
+            const error = new Error('Copy error');
+            mockFs.copyFile.mockRejectedValue(error);
+
+            await expect(copyFile('src.txt', 'dst.txt')).rejects.toThrow(error);
+            expect(mockHandleError).toHaveBeenCalledWith(error, 'copying file from src.txt to dst.txt');
+        });
+    });
+
+    describe('removeDirectory', () => {
+        it('should remove directory successfully', async () => {
+            mockFs.rm.mockResolvedValue();
+
+            await removeDirectory('testDir');
+
+            expect(mockFs.rm).toHaveBeenCalledWith('testDir', { recursive: true, force: true });
+        });
+
+        it('should handle errors when removing directory', async () => {
+            const error = new Error('Remove dir error');
+            mockFs.rm.mockRejectedValue(error);
+
+            await expect(removeDirectory('testDir')).rejects.toThrow(error);
+            expect(mockHandleError).toHaveBeenCalledWith(error, 'removing directory testDir');
+        });
+    });
+
+    describe('fileExists', () => {
+        it('should return true when file exists', async () => {
+            mockFs.access.mockResolvedValue();
+
+            const result = await fileExists('test.txt');
+            expect(result).toBe(true);
+            expect(mockFs.access).toHaveBeenCalledWith('test.txt');
+        });
+
+        it('should return false when file does not exist', async () => {
+            mockFs.access.mockRejectedValue(new Error('File not found'));
+
+            const result = await fileExists('test.txt');
+            expect(result).toBe(false);
+        });
+    });
+
+    describe('isDirectory', () => {
+        it('should return true for directories', async () => {
+            mockFs.stat.mockResolvedValue({ isDirectory: () => true } as Stats);
+
+            const result = await isDirectory('testDir');
+            expect(result).toBe(true);
+            expect(mockFs.stat).toHaveBeenCalledWith('testDir');
+        });
+
+        it('should return false for non-directories', async () => {
+            mockFs.stat.mockResolvedValue({ isDirectory: () => false } as Stats);
+
+            const result = await isDirectory('test.txt');
+            expect(result).toBe(false);
+        });
+
+        it('should return false when path does not exist', async () => {
+            mockFs.stat.mockRejectedValue(new Error('Path not found'));
+
+            const result = await isDirectory('nonexistent');
+            expect(result).toBe(false);
+        });
+    });
+
+    describe('isFile', () => {
+        it('should return true for files', async () => {
+            mockFs.stat.mockResolvedValue({ isFile: () => true } as Stats);
+
+            const result = await isFile('test.txt');
+            expect(result).toBe(true);
+            expect(mockFs.stat).toHaveBeenCalledWith('test.txt');
+        });
+
+        it('should return false for non-files', async () => {
+            mockFs.stat.mockResolvedValue({ isFile: () => false } as Stats);
+
+            const result = await isFile('testDir');
+            expect(result).toBe(false);
+        });
+
+        it('should return false when path does not exist', async () => {
+            mockFs.stat.mockRejectedValue(new Error('Path not found'));
+
+            const result = await isFile('nonexistent');
+            expect(result).toBe(false);
+        });
+    });
+});
diff --git a/src/shared/utils/__tests__/logger.test.ts b/src/shared/utils/__tests__/logger.test.ts
new file mode 100644
index 0000000..0dec515
--- /dev/null
+++ b/src/shared/utils/__tests__/logger.test.ts
@@ -0,0 +1,93 @@
+import logger from '../logger';
+
+jest.mock('../../config/common-config', () => ({
+    commonConfig: {
+        LOG_LEVEL: 'debug'
+    }
+}));
+
+describe('LoggerUtils', () => {
+    let consoleSpy: jest.SpyInstance;
+    const originalEnv = process.env;
+    beforeEach(() => {
+        process.env = { ...originalEnv };
+        delete process.env.LOG_LEVEL;
+
+        logger.setLogLevel('debug');
+
+        consoleSpy = jest.spyOn(console, 'log').mockImplementation();
+    });
+
+    afterEach(() => {
+        consoleSpy.mockRestore();
+        process.env = originalEnv;
+    });
+
+    describe('log levels', () => {
+        it('should log at info level', () => {
+            logger.setLogLevel('info');
+            logger.info('test message');
+            expect(consoleSpy).toHaveBeenCalled();
+            const logMessage = consoleSpy.mock.calls[0][0];
+            expect(logMessage).toContain('[INFO]');
+        });
+
+        it('should log at error level', () => {
+            logger.setLogLevel('error');
+            logger.error('test error');
+            expect(consoleSpy).toHaveBeenCalled();
+            const logMessage = consoleSpy.mock.calls[0][0];
+            expect(logMessage).toContain('[ERROR]');
+        });
+
+        it('should log at warn level', () => {
+            logger.setLogLevel('warn');
+            logger.warn('test warning');
+            expect(consoleSpy).toHaveBeenCalled();
+            const logMessage = consoleSpy.mock.calls[0][0];
+            expect(logMessage).toContain('[WARN]');
+        });
+
+        it('should log at debug level', () => {
+            logger.setLogLevel('debug');
+            logger.debug('test debug');
+            expect(consoleSpy).toHaveBeenCalled();
+            const logMessage = consoleSpy.mock.calls[0][0];
+            expect(logMessage).toContain('[DEBUG]');
+        });
+    });
+
+    describe('setLogLevel', () => {
+        it('should respect log level settings', () => {
+            logger.setLogLevel('error');
+
+            logger.debug('test debug');
+            expect(consoleSpy).not.toHaveBeenCalled();
+
+            logger.info('test info');
+            expect(consoleSpy).not.toHaveBeenCalled();
+
+            logger.warn('test warn');
+            expect(consoleSpy).not.toHaveBeenCalled();
+
+            logger.error('test error');
+            expect(consoleSpy).toHaveBeenCalledTimes(1);
+            expect(consoleSpy.mock.calls[0][0]).toContain('[ERROR]');
+        });
+
+        it('should allow all logs at debug level', () => {
+            logger.setLogLevel('debug');
+
+            logger.debug('test debug');
+            logger.info('test info');
+            logger.warn('test warn');
+            logger.error('test error');
+
+            expect(consoleSpy).toHaveBeenCalledTimes(4);
+            expect(consoleSpy.mock.calls[0][0]).toContain('[DEBUG]');
+            expect(consoleSpy.mock.calls[1][0]).toContain('[INFO]');
+            expect(consoleSpy.mock.calls[2][0]).toContain('[WARN]');
+            expect(consoleSpy.mock.calls[3][0]).toContain('[ERROR]');
+        });
+    });
+});
diff --git a/src/shared/utils/__tests__/prompt-processing.test.ts b/src/shared/utils/__tests__/prompt-processing.test.ts
new file mode 100644
index 0000000..c823dc5
--- /dev/null
+++ b/src/shared/utils/__tests__/prompt-processing.test.ts
@@ -0,0 +1,253 @@
+import { Message, RawMessageStreamEvent } from '@anthropic-ai/sdk/resources/messages.js';
+import { jest } from '@jest/globals';
+
+import { sendAnthropicRequestClassic, sendAnthropicRequestStream } from '../anthropic-client';
+import { updatePromptWithVariables, processPromptContent } from '../prompt-processing';
+
+jest.mock('../anthropic-client');
+const mockSendAnthropicRequestClassic = sendAnthropicRequestClassic as jest.MockedFunction<
+    typeof sendAnthropicRequestClassic
+>;
+const mockSendAnthropicRequestStream = sendAnthropicRequestStream as jest.MockedFunction<
+    typeof sendAnthropicRequestStream
+>;
+describe('PromptProcessingUtils', () => {
+    beforeEach(() => {
+        jest.clearAllMocks();
+
+        jest.spyOn(console, 'log').mockImplementation(() => {});
+        jest.spyOn(console, 'error').mockImplementation(() => {});
+        jest.spyOn(process.stdout, 'write').mockImplementation(() => true);
+    });
+
+    describe('updatePromptWithVariables', () => {
+        it('should replace variables in content with provided values', () => {
+            const content = 'Hello {{name}}, welcome to {{place}}!';
+            const variables = {
+                name: 'John',
+                place: 'Paris'
+            };
+            const result = updatePromptWithVariables(content, variables);
+            expect(result).toBe('Hello John, welcome to Paris!');
+        });
+
+        it('should handle multiple occurrences of the same variable', () => {
+            const content = '{{name}} is {{name}}';
+            const variables = { name: 'John' };
+            const result = updatePromptWithVariables(content, variables);
+            expect(result).toBe('John is John');
+        });
+
+        it('should handle empty variables object', () => {
+            const content = 'Hello {{name}}!';
+            const variables = {};
+            const result = updatePromptWithVariables(content, variables);
+            expect(result).toBe('Hello {{name}}!');
+        });
+
+        it('should throw error for null or undefined content', () => {
+            expect(() => {
+                updatePromptWithVariables(null as unknown as string, {});
+            }).toThrow('Content cannot be null or undefined');
+        });
+
+        it('should throw error if variable value is not a string', () => {
+            const content = 'Hello {{name}}!';
+            const variables = { name: 123 as any };
+            expect(() => {
+                updatePromptWithVariables(content, variables);
+            }).toThrow('Variable value for key "name" must be a string');
+        });
+    });
+
+    describe('processPromptContent', () => {
+        const mockMessages = [
+            { role: 'user', content: 'Hello' },
+            { role: 'assistant', content: 'Hi there!' }
+        ];
+        it('should process classic response correctly', async () => {
+            const mockMessage: Message = {
+                id: 'msg_123',
+                type: 'message',
+                role: 'assistant',
+                content: [{ type: 'text', text: 'Test response' }],
+                model: 'claude-2',
+                stop_reason: null,
+                stop_sequence: null,
+                usage: { input_tokens: 10, output_tokens: 20 }
+            };
+            mockSendAnthropicRequestClassic.mockResolvedValue(mockMessage);
+
+            const result = await processPromptContent(mockMessages, false, false);
+            expect(result).toBe('Test response');
+            expect(mockSendAnthropicRequestClassic).toHaveBeenCalledWith(mockMessages);
+        });
+
+        it('should process streaming response correctly', async () => {
+            const mockStream = [
+                { type: 'content_block_delta', index: 0, delta: { type: 'text_delta', text: 'Hello' } as const },
+                { type: 'content_block_delta', index: 1, delta: { type: 'text_delta', text: ' world' } as const }
+            ];
+            mockSendAnthropicRequestStream.mockImplementation(async function* () {
+                for (const event of mockStream) {
+                    yield event as RawMessageStreamEvent;
+                }
+            });
+
+            const result = await processPromptContent(mockMessages, true, false);
+            expect(result).toBe('Hello world');
+            expect(mockSendAnthropicRequestStream).toHaveBeenCalledWith(mockMessages);
+        });
+
+        it('should handle complex message content', async () => {
+            const mockMessage: Message = {
+                id: 'msg_123',
+                type: 'message',
+                role: 'assistant',
+                content: [
+                    { type: 'text', text: 'Text content' },
+                    {
+                        type: 'tool_use',
+                        id: 'tool_123',
+                        name: 'calculator',
+                        input: { expression: '2+2' }
+                    }
+                ],
+                model: 'claude-2',
+                stop_reason: null,
+                stop_sequence: null,
+                usage: { input_tokens: 10, output_tokens: 20 }
+            };
+            mockSendAnthropicRequestClassic.mockResolvedValue(mockMessage);
+
+            const result = await processPromptContent(mockMessages, false, false);
+            expect(result).toContain('Text content');
+            expect(result).toContain('[Tool Use: calculator]');
+            expect(result).toContain('Input: {"expression":"2+2"}');
+        });
+
+        it('should handle unknown block types in message content', async () => {
+            const mockMessage: Message = {
+                id: 'msg_456',
+                type: 'message',
+                role: 'assistant',
+                content: [{ type: 'text', text: 'Known text' }, { type: 'unknown_type', data: 'Some data' } as any],
+                model: 'claude-2',
+                stop_reason: null,
+                stop_sequence: null,
+                usage: { input_tokens: 15, output_tokens: 25 }
+            };
+            mockSendAnthropicRequestClassic.mockResolvedValue(mockMessage);
+
+            const result = await processPromptContent(mockMessages, false, false);
+            expect(result).toContain('Known text');
+            expect(result).toContain(JSON.stringify({ type: 'unknown_type', data: 'Some data' }));
+        });
+
+        it('should handle invalid blocks in message content', async () => {
+            const mockMessage: Message = {
+                id: 'msg_789',
+                type: 'message',
+                role: 'assistant',
+                content: [{ type: 'text', text: 'Valid text' }, null as any, undefined as any],
+                model: 'claude-2',
+                stop_reason: null,
+                stop_sequence: null,
+                usage: { input_tokens: 20, output_tokens: 30 }
+            };
+            mockSendAnthropicRequestClassic.mockResolvedValue(mockMessage);
+
+            const result = await processPromptContent(mockMessages, false, false);
+            expect(result).toBe('Valid text');
+        });
+
+        it('should handle errors in classic mode', async () => {
+            mockSendAnthropicRequestClassic.mockRejectedValue(new Error('API Error'));
+
+            await expect(processPromptContent(mockMessages, false, false)).rejects.toThrow('API Error');
+        });
+
+        it('should handle errors in streaming mode', async () => {
+            mockSendAnthropicRequestStream.mockImplementation(async function* () {
+                yield { type: 'placeholder' } as unknown as RawMessageStreamEvent;
+                throw new Error('Stream Error');
+            });
+
+            await expect(processPromptContent(mockMessages, true, false)).rejects.toThrow('Stream Error');
+        });
+
+        it('should throw error if messages array is empty', async () => {
+            await expect(processPromptContent([], false, false)).rejects.toThrow('Messages must be a non-empty array');
+        });
+
+        it('should log messages when logging is true', async () => {
+            const mockMessage: Message = {
+                id: 'msg_101',
+                type: 'message',
+                role: 'assistant',
+                content: [{ type: 'text', text: 'Logged response' }],
+                model: 'claude-2',
+                stop_reason: null,
+                stop_sequence: null,
+                usage: { input_tokens: 5, output_tokens: 15 }
+            };
+            mockSendAnthropicRequestClassic.mockResolvedValue(mockMessage);
+
+            const consoleLogSpy = jest.spyOn(console, 'log').mockImplementation(() => {});
+            await processPromptContent(mockMessages, false, true);
+
+            expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('You:'));
+            expect(consoleLogSpy).toHaveBeenCalledWith('Hi there!');
+            expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('AI:'));
+
+            consoleLogSpy.mockRestore();
+        });
+
+        it('should return empty string if message content is empty', async () => {
+            const mockMessage: Message = {
+                id: 'msg_202',
+                type: 'message',
+                role: 'assistant',
+                content: [],
+                model: 'claude-2',
+                stop_reason: null,
+                stop_sequence: null,
+                usage: { input_tokens: 0, output_tokens: 0 }
+            };
+            mockSendAnthropicRequestClassic.mockResolvedValue(mockMessage);
+
+            const result = await processPromptContent(mockMessages, false, false);
+            expect(result).toBe('');
+        });
+
+        it('should process streaming response with partial_json correctly', async () => {
+            const mockStream = [
+                {
+                    type: 'content_block_delta',
+                    index: 0,
+                    delta: { type: 'partial_json', partial_json: '{"key":' } as const
+                },
+                {
+                    type: 'content_block_delta',
+                    index: 1,
+                    delta: { type: 'partial_json', partial_json: '"value"}' } as const
+                }
+            ];
+            mockSendAnthropicRequestStream.mockImplementation(async function* () {
+                for (const event of mockStream) {
+                    yield event as RawMessageStreamEvent;
+                }
+            });
+
+            const processStdoutWriteSpy = jest.spyOn(process.stdout, 'write').mockImplementation(() => true);
+            const result = await processPromptContent(mockMessages, true, false);
+            expect(result).toBe('{"key":"value"}');
+            expect(mockSendAnthropicRequestStream).toHaveBeenCalledWith(mockMessages);
+
+            expect(processStdoutWriteSpy).toHaveBeenCalledWith('{"key":');
+            expect(processStdoutWriteSpy).toHaveBeenCalledWith('"value"}');
+
+            processStdoutWriteSpy.mockRestore();
+        });
+    });
+});
diff --git a/src/shared/utils/__tests__/string-formatter.test.ts b/src/shared/utils/__tests__/string-formatter.test.ts
new file mode 100644
index 0000000..e530ecd
--- /dev/null
+++ b/src/shared/utils/__tests__/string-formatter.test.ts
@@ -0,0 +1,23 @@
+import { formatTitleCase, formatSnakeCase } from '../string-formatter';
+
+describe('StringFormatterUtils', () => {
+    describe('formatTitleCase', () => {
+        it('should format string to title case', () => {
+            expect(formatTitleCase('hello_world')).toBe('Hello World');
+            expect(formatTitleCase('test-case')).toBe('Test Case');
+        });
+    });
+
+    describe('formatSnakeCase', () => {
+        it('should format string to snake case', () => {
+            expect(formatSnakeCase('Hello World')).toBe('hello_world');
+            expect(formatSnakeCase('TestCase')).toBe('test_case');
+            expect(formatSnakeCase('{TEST_VAR}')).toBe('test_var');
+        });
+
+        it('should handle special characters', () => {
+            expect(formatSnakeCase('Hello {World}')).toBe('hello_world');
+            expect(formatSnakeCase('TEST_VAR')).toBe('test_var');
+        });
+    });
+});
diff --git a/src/shared/utils/anthropic_client.util.ts b/src/shared/utils/anthropic-client.ts
similarity index 94%
rename from src/shared/utils/anthropic_client.util.ts
rename to src/shared/utils/anthropic-client.ts
index 5bfab25..bdcdf36 100644
--- a/src/shared/utils/anthropic_client.util.ts
+++ b/src/shared/utils/anthropic-client.ts
@@ -1,9 +1,9 @@
 import { Anthropic } from '@anthropic-ai/sdk';
 import { Message, MessageStreamEvent } from '@anthropic-ai/sdk/resources';
 
-import { AppError, handleError } from '../../cli/utils/error.util';
+import { AppError, handleError } from '../../cli/utils/errors';
 import { getConfigValue } from '../config';
-import { commonConfig } from '../config/common.config';
+import { commonConfig } from '../config/common-config';
 
 let anthropicClient: Anthropic | null = null;
 
diff --git a/src/shared/utils/file_system.util.ts b/src/shared/utils/file-system.ts
similarity index 93%
rename from src/shared/utils/file_system.util.ts
rename to src/shared/utils/file-system.ts
index ba6ea09..755aeac 100644
--- a/src/shared/utils/file_system.util.ts
+++ b/src/shared/utils/file-system.ts
@@ -1,6 +1,6 @@
 import * as fs from 'fs/promises';
 
-import { handleError } from '../../cli/utils/error.util';
+import { handleError } from '../../cli/utils/errors';
 
 export async function readFileContent(filePath: string): Promise<string> {
     try {
@@ -22,7 +22,8 @@ export async function writeFileContent(filePath: string, content: string): Promi
 
 export async function readDirectory(dirPath: string): Promise<string[]> {
     try {
-        return await fs.readdir(dirPath);
+        const entries = await fs.readdir(dirPath, { withFileTypes: false });
+        return entries;
     } catch (error) {
         handleError(error, `reading directory ${dirPath}`);
         throw error;
diff --git a/src/shared/utils/logger.util.ts b/src/shared/utils/logger.ts
similarity index 86%
rename from src/shared/utils/logger.util.ts
rename to src/shared/utils/logger.ts
index 85e2a90..5a1885b 100644
--- a/src/shared/utils/logger.util.ts
+++ b/src/shared/utils/logger.ts
@@ -1,6 +1,6 @@
 import chalk from 'chalk';
 
-import { commonConfig } from '../config/common.config';
+import { commonConfig } from '../config/common-config';
 
 enum LogLevel {
     DEBUG,
@@ -33,8 +33,9 @@ function normalizeLogLevel(level: LogLevelKey): keyof typeof LogLevel {
 class ConfigurableLogger implements Logger {
     private currentLogLevel: LogLevel;
 
-    constructor(initialLogLevel: LogLevelKey = commonConfig.LOG_LEVEL) {
-        this.currentLogLevel = LogLevel[normalizeLogLevel(initialLogLevel)];
+    constructor(initialLogLevel?: LogLevelKey) {
+        const logLevel = initialLogLevel || (process.env.LOG_LEVEL as LogLevelKey) || commonConfig.LOG_LEVEL;
+        this.currentLogLevel = LogLevel[normalizeLogLevel(logLevel)];
     }
 
     setLogLevel(level: LogLevelKey): void {
diff --git a/src/shared/utils/prompt_processing.util.ts b/src/shared/utils/prompt-processing.ts
similarity index 71%
rename from src/shared/utils/prompt_processing.util.ts
rename to src/shared/utils/prompt-processing.ts
index 227b360..b93ab2d 100644
--- a/src/shared/utils/prompt_processing.util.ts
+++ b/src/shared/utils/prompt-processing.ts
@@ -1,13 +1,21 @@
 import { Message } from '@anthropic-ai/sdk/resources';
 import chalk from 'chalk';
 
-import { sendAnthropicRequestClassic, sendAnthropicRequestStream } from './anthropic_client.util';
-import { handleError } from '../../cli/utils/error.util';
+import { sendAnthropicRequestClassic, sendAnthropicRequestStream } from './anthropic-client';
+import { handleError } from '../../cli/utils/errors';
 
 export function updatePromptWithVariables(content: string, variables: Record<string, string>): string {
+    if (content === null || content === undefined) {
+        throw new Error('Content cannot be null or undefined');
+    }
+
     try {
         return Object.entries(variables).reduce((updatedContent, [key, value]) => {
-            const regex = new RegExp(`{{${key.replace(/{{|}}/g, '')}}}`, 'g');
+            if (typeof value !== 'string') {
+                throw new Error(`Variable value for key "${key}" must be a string`);
+            }
+
+            const regex = new RegExp(`{{${key.replace(/[{}]/g, '')}}}`, 'g');
             return updatedContent.replace(regex, value);
         }, content);
     } catch (error) {
@@ -17,18 +25,23 @@ export function updatePromptWithVariables(content: string, variables: Record<str
 }
 
 function extractContentFromMessage(message: Message): string {
-    if (!message.content || message.content.length === 0) {
+    if (!message || !message.content || !Array.isArray(message.content) || message.content.length === 0) {
         return '';
     }
     return message.content
         .map((block) => {
+            if (!block || typeof block !== 'object') {
+                return '';
+            }
+
             if (block.type === 'text') {
-                return block.text;
+                return block.text || '';
             } else if (block.type === 'tool_use') {
                 return `[Tool Use: ${block.name}]\nInput: ${JSON.stringify(block.input)}`;
             }
             return JSON.stringify(block);
         })
+        .filter(Boolean)
         .join('\n');
 }
 
@@ -37,6 +50,10 @@ export async function processPromptContent(
     useStreaming: boolean = false,
     logging: boolean = true
 ): Promise<string> {
+    if (!Array.isArray(messages) || messages.length === 0) {
+        throw new Error('Messages must be a non-empty array');
+    }
+
     try {
         if (logging) {
             console.log(chalk.blue(chalk.bold('\nYou:')));
@@ -57,11 +74,15 @@ export async function processPromptContent(
 }
 
 async function processStreamingResponse(messages: { role: string; content: string }[]): Promise<string> {
+    if (!Array.isArray(messages)) {
+        throw new Error('Messages must be an array');
+    }
+
     let fullResponse = '';
 
     try {
         for await (const event of sendAnthropicRequestStream(messages)) {
-            if (event.type === 'content_block_delta' && event.delta) {
+            if (event?.type === 'content_block_delta' && event.delta) {
                 if ('text' in event.delta) {
                     fullResponse += event.delta.text;
                     process.stdout.write(event.delta.text);
diff --git a/src/shared/utils/string_formatter.util.ts b/src/shared/utils/string-formatter.ts
similarity index 62%
rename from src/shared/utils/string_formatter.util.ts
rename to src/shared/utils/string-formatter.ts
index 19bfd42..dc2fded 100644
--- a/src/shared/utils/string_formatter.util.ts
+++ b/src/shared/utils/string-formatter.ts
@@ -1,6 +1,6 @@
 export function formatTitleCase(category: string): string {
     return category
-        .split('_')
+        .split(/[_-]/)
         .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
         .join(' ');
 }
@@ -8,9 +8,9 @@ export function formatTitleCase(category: string): string {
 export function formatSnakeCase(variableName: string): string {
     return variableName
         .replace(/[{}]/g, '')
+        .replace(/([a-z])([A-Z])/g, '$1_$2')
         .toLowerCase()
-        .replace(/_/g, ' ')
-        .replace(/\w\S*/g, (word) => word.charAt(0).toUpperCase() + word.substr(1).toLowerCase())
-        .replace(/ /g, '_')
-        .toLowerCase();
+        .replace(/[-\s_]+/g, '_')
+        .replace(/^_/, '')
+        .replace(/_$/g, '');
 }
diff --git a/tests/.gitkeep b/tests/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/tsconfig.json b/tsconfig.json
index 83556d5..e2c7e75 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -15,5 +15,5 @@
         "typeRoots": ["src/shared/types", "./node_modules/@types"]
     },
     "include": ["src/**/*"],
-    "exclude": ["node_modules", "dist", "tests"]
+    "exclude": ["node_modules", "dist", "**/__tests__/**"]
 }
\ No newline at end of file
diff --git a/tsconfig.test.json b/tsconfig.test.json
index d2f7a15..efe911b 100644
--- a/tsconfig.test.json
+++ b/tsconfig.test.json
@@ -2,7 +2,10 @@
     "extends": "./tsconfig.json",
     "compilerOptions": {
         "module": "commonjs",
-        "types": ["jest", "node"]
+        "types": ["jest", "node"],
+        "rootDir": ".",
+        "noEmit": true
     },
-    "include": ["src/**/*", "tests/**/*"]
+    "include": ["src/**/*", "src/**/__tests__/**/*"],
+    "exclude": ["node_modules", "dist"]
 }
\ No newline at end of file