diff --git a/packages/core/package.json b/packages/core/package.json
index a80cf38b72..719b5508bc 100644
--- a/packages/core/package.json
+++ b/packages/core/package.json
@@ -4,7 +4,10 @@
   "version": "2.4.0",
   "license": "MIT",
   "type": "module",
-  "repository": "github:microsoft/genaiscript",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/microsoft/genaiscript.git"
+  },
   "bugs": {
     "url": "https://github.com/microsoft/genaiscript/issues"
   },
@@ -175,5 +178,13 @@
   },
   "main": "./dist/commonjs/index.js",
   "types": "./dist/commonjs/index.d.ts",
-  "module": "./dist/esm/index.js"
+  "module": "./dist/esm/index.js",
+  "description": "Core package for the GenAIScript project, which provides the foundational libraries and tools to build and execute GenAIScript code.",
+  "directories": {
+    "doc": "docs",
+    "test": "test"
+  },
+  "keywords": [],
+  "author": "",
+  "homepage": "https://github.com/microsoft/genaiscript#readme"
 }
diff --git a/packages/core/src/mustache.ts b/packages/core/src/mustache.ts
index c6bd476a16..406552b2c1 100644
--- a/packages/core/src/mustache.ts
+++ b/packages/core/src/mustache.ts
@@ -1,14 +1,14 @@
 // Copyright (c) Microsoft Corporation.
 // Licensed under the MIT License.
 
-import { splitMarkdown } from "./frontmatter.js";
+import { splitMarkdown, frontmatterTryParse } from "./frontmatter.js";
 import Mustache from "mustache";
 import { jinjaRender } from "./jinja.js";
 import type { ImportTemplateOptions } from "./types.js";
 
 /**
  * Processes a markdown string by applying Mustache or Jinja templating.
- * Removes frontmatter, prompty roles, and XML tags before interpolation.
+ * Extracts frontmatter parameters and merges them with provided data before interpolation.
  * @param md The markdown string to process.
  * @param data The data for variable interpolation.
  * @param options Configuration for templating format, e.g., Mustache or Jinja.
@@ -19,11 +19,45 @@ export async function interpolateVariables(
   data: Record<string, any>,
   options?: ImportTemplateOptions,
 ): Promise<string> {
-  if (!md || !data) return md;
+  if (!md) return md;
   const { format } = options || {};
-  // remove frontmatter
+
+  // Extract frontmatter and content
   let { content } = splitMarkdown(md);
 
+  // Extract parameters from frontmatter and merge with provided data
+  const frontmatter = frontmatterTryParse(md);
+  let mergedData = { ...(data ?? {}) };
+
+  if (frontmatter?.value) {
+    // Extract default values from frontmatter parameters or inputs (prompty format)
+    const frontmatterDefaults: Record<string, any> = {};
+    const parameterSource = frontmatter.value.parameters || frontmatter.value.inputs;
+
+    if (parameterSource) {
+      for (const [key, param] of Object.entries(parameterSource)) {
+        if (typeof param === "object" && param !== null && "default" in param) {
+          // Only use frontmatter default if no data provided for this key
+          if (!(key in mergedData)) {
+            frontmatterDefaults[key] = param.default;
+          }
+        }
+      }
+      // Merge frontmatter defaults with provided data (data takes precedence)
+      mergedData = { ...frontmatterDefaults, ...mergedData };
+    }
+
+    // Handle prompty sample data as defaults
+    if (frontmatter.value.sample && typeof frontmatter.value.sample === "object") {
+      for (const [key, value] of Object.entries(frontmatter.value.sample)) {
+        if (!(key in mergedData)) {
+          frontmatterDefaults[key] = value;
+        }
+      }
+      mergedData = { ...frontmatterDefaults, ...mergedData };
+    }
+  }
+
   // remove prompty roles
   // https://github.com/microsoft/prompty/blob/main/runtime/prompty/prompty/parsers.py#L113C21-L113C77
   content = content.replace(/^\s*(system|user|assistant)\s*:\s*$/gim, "\n");
@@ -31,8 +65,8 @@ export async function interpolateVariables(
   if (content) {
     // remove xml tags
     // https://humanloop.com/docs/prompt-file-format
-    if (format === "jinja") content = jinjaRender(content, data ?? {});
-    else content = Mustache.render(content, data ?? {});
+    if (format === "jinja") content = jinjaRender(content, mergedData);
+    else content = Mustache.render(content, mergedData);
   }
 
   return content;
diff --git a/packages/core/src/template.ts b/packages/core/src/template.ts
index eefabb8526..a3b174ddf5 100644
--- a/packages/core/src/template.ts
+++ b/packages/core/src/template.ts
@@ -15,7 +15,14 @@ import { deleteUndefinedValues } from "./cleaners.js";
 import { markdownScriptParse } from "./markdownscript.js";
 import { readJSON } from "./fs.js";
 import { frontmatterTryParse } from "./frontmatter.js";
-import type { PromptArgs, PromptScript, McpServersConfig, McpServerConfig, McpAgentServersConfig, McpAgentServerConfig } from "./types.js";
+import type {
+  PromptArgs,
+  PromptScript,
+  McpServersConfig,
+  McpServerConfig,
+  McpAgentServersConfig,
+  McpAgentServerConfig,
+} from "./types.js";
 import { basename, resolve, dirname } from "node:path";
 import { readText } from "./fs.js";
 
@@ -41,10 +48,10 @@ export function templateIdFromFileName(filename: string) {
  */
 async function resolveMcpServersConfig(
   mcpServers: McpServersConfig | undefined,
-  scriptPath: string
+  scriptPath: string,
 ): Promise<Record<string, Omit<McpServerConfig, "id" | "options">> | undefined> {
   if (!mcpServers) return undefined;
-  
+
   if (typeof mcpServers === "string") {
     // Handle file path - resolve relative to script directory
     const configPath = resolve(dirname(scriptPath), mcpServers);
@@ -55,7 +62,9 @@ async function resolveMcpServersConfig(
         if (config.mcpServers && typeof config.mcpServers === "object") {
           return config.mcpServers as Record<string, Omit<McpServerConfig, "id" | "options">>;
         } else {
-          throw new Error(`Invalid MCP server configuration format in ${configPath}. Configuration must have a root 'mcpServers' field.`);
+          throw new Error(
+            `Invalid MCP server configuration format in ${configPath}. Configuration must have a root 'mcpServers' field.`,
+          );
         }
       } else {
         throw new Error(`Invalid MCP server configuration format in ${configPath}`);
@@ -77,10 +86,10 @@ async function resolveMcpServersConfig(
  */
 async function resolveMcpAgentServersConfig(
   mcpAgentServers: McpAgentServersConfig | undefined,
-  scriptPath: string
+  scriptPath: string,
 ): Promise<Record<string, Omit<McpAgentServerConfig, "id" | "options">> | undefined> {
   if (!mcpAgentServers) return undefined;
-  
+
   if (typeof mcpAgentServers === "string") {
     // Handle file path - resolve relative to script directory
     const configPath = resolve(dirname(scriptPath), mcpAgentServers);
@@ -89,9 +98,14 @@ async function resolveMcpAgentServersConfig(
       if (typeof config === "object" && config !== null) {
         // Require Claude format with root mcpAgentServers field
         if (config.mcpAgentServers && typeof config.mcpAgentServers === "object") {
-          return config.mcpAgentServers as Record<string, Omit<McpAgentServerConfig, "id" | "options">>;
+          return config.mcpAgentServers as Record<
+            string,
+            Omit<McpAgentServerConfig, "id" | "options">
+          >;
         } else {
-          throw new Error(`Invalid MCP agent server configuration format in ${configPath}. Configuration must have a root 'mcpAgentServers' field.`);
+          throw new Error(
+            `Invalid MCP agent server configuration format in ${configPath}. Configuration must have a root 'mcpAgentServers' field.`,
+          );
         }
       } else {
         throw new Error(`Invalid MCP agent server configuration format in ${configPath}`);
@@ -152,11 +166,15 @@ function parsePromptScriptTools(jsSource: string) {
  */
 function extractFrontmatterParameters(content: string): Record<string, any> | undefined {
   const fm = frontmatterTryParse(content);
-  if (!fm?.value?.parameters) return undefined;
-  
+  if (!fm?.value) return undefined;
+
+  // Handle both 'parameters' and 'inputs' (prompty format)
+  const parameterSource = fm.value.parameters || fm.value.inputs;
+  if (!parameterSource) return undefined;
+
   // Return the parameters directly - they should already be in the correct format
   // with type definitions like { type: "string", default: "value" }
-  return fm.value.parameters;
+  return parameterSource;
 }
 
 /**
@@ -212,16 +230,16 @@ async function parsePromptTemplateCore(filename: string, content: string) {
  */
 export async function parsePromptScript(filename: string, content: string) {
   const script = await parsePromptTemplateCore(filename, content);
-  
+
   // Extract frontmatter parameters from markdown files and merge them
   // This handles the case where markdown scripts define parameters in frontmatter
   const frontmatterParameters = extractFrontmatterParameters(content);
   if (frontmatterParameters) {
     script.parameters = {
       ...(script.parameters || {}),
-      ...frontmatterParameters
+      ...frontmatterParameters,
     };
   }
-  
+
   return script;
 }
diff --git a/packages/core/test/mustache.test.ts b/packages/core/test/mustache.test.ts
index 6a788dbd82..89bd04589d 100644
--- a/packages/core/test/mustache.test.ts
+++ b/packages/core/test/mustache.test.ts
@@ -120,12 +120,106 @@ parameters:
     default: 3
 ---
 Hello {{name}}! This message will repeat {{count}} times.`;
-        
+
     const output = await interpolateVariables(md, {
       name: "GenAI",
       count: 5,
     });
-        
+
     assert.strictEqual(output, `Hello GenAI! This message will repeat 5 times.`);
   });
+
+  test("should use frontmatter parameter defaults when no data provided", async () => {
+    const md = `---
+parameters:
+  name:
+    type: string
+    default: "World"
+  count:
+    type: number
+    default: 3
+---
+Hello {{name}}! This message will repeat {{count}} times.`;
+
+    const output = await interpolateVariables(md, {});
+
+    assert.strictEqual(output, `Hello World! This message will repeat 3 times.`);
+  });
+
+  test("should handle partial data with frontmatter defaults", async () => {
+    const md = `---
+parameters:
+  name:
+    type: string
+    default: "World"
+  count:
+    type: number
+    default: 3
+---
+Hello {{name}}! This message will repeat {{count}} times.`;
+
+    const output = await interpolateVariables(md, {
+      name: "GenAI",
+      // count should use default from frontmatter
+    });
+
+    assert.strictEqual(output, `Hello GenAI! This message will repeat 3 times.`);
+  });
+
+  test("should handle frontmatter parameters with Jinja format", async () => {
+    const md = `---
+parameters:
+  name:
+    type: string
+    default: "World"
+  count:
+    type: number
+    default: 3
+---
+Hello {{ name }}! This message will repeat {{ count }} times.`;
+
+    const output = await interpolateVariables(
+      md,
+      {
+        name: "GenAI",
+      },
+      { format: "jinja" },
+    );
+
+    assert.strictEqual(output, `Hello GenAI! This message will repeat 3 times.`);
+  });
+
+  test("should handle prompty format with inputs and sample", async () => {
+    const md = `---
+name: Basic Prompt
+description: A basic prompt
+inputs:
+  question:
+    type: string
+sample:
+  "question": "What is the capital of France?"
+---
+Question: {{question}}`;
+
+    const output = await interpolateVariables(md, {});
+
+    assert.strictEqual(output, `Question: What is the capital of France?`);
+  });
+
+  test("should handle prompty format with data override", async () => {
+    const md = `---
+inputs:
+  question:
+    type: string
+sample:
+  "question": "Default question"
+---
+Question: {{question}}`;
+
+    const output = await interpolateVariables(md, {
+      question: "Custom question",
+    });
+
+    assert.strictEqual(output, `Question: Custom question`);
+  });
 });
