diff --git a/public/assets/css/home.css b/public/assets/css/home.css index 4353b78..c4c0625 100644 --- a/public/assets/css/home.css +++ b/public/assets/css/home.css @@ -9,24 +9,47 @@ body { padding-top: 0; } align-items: center; justify-content: center; overflow: hidden; - background: #0a0a0a; + background: #0c0817; + } + + /* Blurred logo mountains — same technique Lovable uses with their hat */ + .hero::before { + content: ''; + position: absolute; + left: 50%; + top: 56%; + transform: translate(-50%, -50%); + width: 680px; + height: 680px; + background: url('/assets/img/logo/traverse_icon_512x512.svg') center / contain no-repeat; + filter: blur(72px); + opacity: 0.55; + z-index: 1; + pointer-events: none; } + .hero-gradient { position: absolute; inset: 0; pointer-events: none; z-index: 0; background: - radial-gradient(ellipse 70% 55% at 18% 115%, rgba(255, 130, 20, 0.72) 0%, transparent 52%), - radial-gradient(ellipse 60% 50% at 55% 115%, rgba(210, 30, 120, 0.58) 0%, transparent 52%), - radial-gradient(ellipse 70% 55% at 88% 115%, rgba(110, 10, 220, 0.52) 0%, transparent 52%), - radial-gradient(ellipse 120% 45% at 50% 125%, rgba(60, 0, 160, 0.4) 0%, transparent 58%); + radial-gradient(ellipse 75% 60% at 15% 100%, rgba(255, 130, 20, 0.80) 0%, transparent 50%), + radial-gradient(ellipse 65% 55% at 52% 100%, rgba(210, 30, 120, 0.70) 0%, transparent 50%), + radial-gradient(ellipse 75% 60% at 88% 100%, rgba(110, 10, 220, 0.65) 0%, transparent 50%), + radial-gradient(ellipse 130% 50% at 50% 110%, rgba(60, 0, 160, 0.45) 0%, transparent 55%); } .hero-gradient::after { content: ''; position: absolute; inset: 0; - background: linear-gradient(to bottom, #0c0817 0%, #0c0817 18%, rgba(12,8,23,0.6) 52%, transparent 72%); + background: linear-gradient( + to bottom, + rgba(12,8,23,0.72) 0%, + rgba(12,8,23,0.45) 30%, + rgba(12,8,23,0.15) 58%, + transparent 78% + ); } .hero-content { position: relative; diff --git a/scripts/convert.py b/scripts/convert.py index 427ebad..7dfadd6 100644 --- a/scripts/convert.py +++ b/scripts/convert.py @@ -75,6 +75,13 @@ def get_json_ld(html: str) -> str: return m.group(1).strip() if m else "" +def get_inline_styles(html: str) -> str: + """Extract inline ', html, re.DOTALL) + combined = '\n'.join(s.strip() for s in styles) + return combined.strip() + + def get_body_content(html: str) -> str: """Extract everything between the end of nav-mobile-menu div and the footer.""" # Find end of nav-mobile-menu @@ -91,6 +98,9 @@ def get_body_content(html: str) -> str: footer_start = html.rfind('') content = html[nav_end:footer_start].strip() + # Strip old inline breadcrumb divs (replaced by SubpageLayout's Breadcrumb component) + content = re.sub(r']*>.*?', '', content, flags=re.DOTALL) + content = re.sub(r']*aria-label=["\']breadcrumb["\'][^>]*>.*?', '', content, flags=re.DOTALL) return content @@ -118,8 +128,9 @@ def escape_backtick(s: str) -> str: return s.replace('`', r'\`').replace('$', r'\$') -def convert_question(html_path: Path, rel_parts: list[str]): - html = html_path.read_text(encoding="utf-8") +def convert_question(html_path: Path, rel_parts: list[str], html: str = None): + if html is None: + html = html_path.read_text(encoding="utf-8") title = get_tag_text(html, "title") # Strip the site suffix for display display_title = re.sub(r'\s*[—–-]\s*Traverse Framework$', '', title).strip() @@ -163,8 +174,9 @@ def convert_question(html_path: Path, rel_parts: list[str]): return out -def convert_subpage(html_path: Path, rel_parts: list[str]): - html = html_path.read_text(encoding="utf-8") +def convert_subpage(html_path: Path, rel_parts: list[str], html: str = None): + if html is None: + html = html_path.read_text(encoding="utf-8") title = get_tag_text(html, "title") description = get_description(html) canonical = get_canonical(html) @@ -185,6 +197,9 @@ def convert_subpage(html_path: Path, rel_parts: list[str]): json_ld_const = f'\nconst _jsonLd = {json.dumps(json_ld, ensure_ascii=False)};' if json_ld else '' json_ld_prop = '\n jsonLd={_jsonLd}' if json_ld else '' + inline_css = get_inline_styles(html) + style_slot = f'\n ' if inline_css else '' + out = f"""--- import SubpageLayout from '@layouts/SubpageLayout.astro'; @@ -195,7 +210,7 @@ def convert_subpage(html_path: Path, rel_parts: list[str]): description={{{json.dumps(description, ensure_ascii=False)}}} canonical={{{json.dumps(canonical, ensure_ascii=False)}}}{json_ld_prop} crumbs={crumbs_code} -> +>{style_slot} """ @@ -231,9 +246,9 @@ def process_file(html_path: Path): html = html_path.read_text(encoding="utf-8") if folder == "questions": - content = convert_question(html_path, folder_parts) + content = convert_question(html_path, folder_parts, html) else: - content = convert_subpage(html_path, folder_parts) + content = convert_subpage(html_path, folder_parts, html) out_path.write_text(content, encoding="utf-8") print(f" ✓ {rel} → src/pages/{'/'.join(folder_parts)}/{stem}.astro") diff --git a/src/layouts/SubpageLayout.astro b/src/layouts/SubpageLayout.astro index b6348a4..af04595 100644 --- a/src/layouts/SubpageLayout.astro +++ b/src/layouts/SubpageLayout.astro @@ -7,22 +7,20 @@ export interface Props { description: string; canonical?: string; jsonLd?: string; - label?: string; crumbs?: Array<{ label: string; href?: string }>; } -const { title, description, canonical, jsonLd, label, crumbs = [] } = Astro.props; +const { title, description, canonical, jsonLd, crumbs = [] } = Astro.props; --- +
-
-
- {crumbs.length > 0 && } - {label &&
{label}
} - + {crumbs.length > 0 && ( +
+
- -
+ )} +
@@ -31,7 +29,8 @@ const { title, description, canonical, jsonLd, label, crumbs = [] } = Astro.prop padding-top: var(--nav-h); min-height: 100vh; } - .subpage-header { - padding: 3.5rem 0 2rem; + .subpage-breadcrumb { + padding-top: 1.25rem; + padding-bottom: 0; } diff --git a/src/pages/about.astro b/src/pages/about.astro index 95d1dcd..115e3a2 100644 --- a/src/pages/about.astro +++ b/src/pages/about.astro @@ -9,5 +9,190 @@ const _body = "
\n
\n + diff --git a/src/pages/blog/ai-agents-need-contracts.astro b/src/pages/blog/ai-agents-need-contracts.astro index b2dd5e0..822bdfa 100644 --- a/src/pages/blog/ai-agents-need-contracts.astro +++ b/src/pages/blog/ai-agents-need-contracts.astro @@ -9,5 +9,42 @@ const _body = "
\n
\n < canonical={"https://traverse-framework.com/blog/ai-agents-need-contracts.html"} crumbs={[{ label: "Home", href: "/" }, { label: "Blog", href: "/blog/" }]} > + diff --git a/src/pages/blog/logic-duplication.astro b/src/pages/blog/logic-duplication.astro index 096f59f..963cc85 100644 --- a/src/pages/blog/logic-duplication.astro +++ b/src/pages/blog/logic-duplication.astro @@ -9,5 +9,159 @@ const _body = "
\n
\n < canonical={"https://traverse-framework.com/blog/logic-duplication.html"} crumbs={[{ label: "Home", href: "/" }, { label: "Blog", href: "/blog/" }]} > + diff --git a/src/pages/blog/runtime-assumptions.astro b/src/pages/blog/runtime-assumptions.astro index c8a62bd..af9ce8f 100644 --- a/src/pages/blog/runtime-assumptions.astro +++ b/src/pages/blog/runtime-assumptions.astro @@ -9,5 +9,42 @@ const _body = "
\n
\n < canonical={"https://traverse-framework.com/blog/runtime-assumptions.html"} crumbs={[{ label: "Home", href: "/" }, { label: "Blog", href: "/blog/" }]} > + diff --git a/src/pages/blog/uma-explained.astro b/src/pages/blog/uma-explained.astro index eb77869..093c136 100644 --- a/src/pages/blog/uma-explained.astro +++ b/src/pages/blog/uma-explained.astro @@ -9,5 +9,47 @@ const _body = "
\n
\n < canonical={"https://traverse-framework.com/blog/uma-explained.html"} crumbs={[{ label: "Home", href: "/" }, { label: "Blog", href: "/blog/" }]} > + diff --git a/src/pages/blog/wasm-business-logic.astro b/src/pages/blog/wasm-business-logic.astro index 48b246f..aad6de6 100644 --- a/src/pages/blog/wasm-business-logic.astro +++ b/src/pages/blog/wasm-business-logic.astro @@ -9,5 +9,37 @@ const _body = "
\n
\n < canonical={"https://traverse-framework.com/blog/wasm-business-logic.html"} crumbs={[{ label: "Home", href: "/" }, { label: "Blog", href: "/blog/" }]} > + diff --git a/src/pages/changelog.astro b/src/pages/changelog.astro index d77fbfc..3d47c26 100644 --- a/src/pages/changelog.astro +++ b/src/pages/changelog.astro @@ -9,5 +9,52 @@ const _body = "
\n
+ diff --git a/src/pages/compare/vs-function-calling.astro b/src/pages/compare/vs-function-calling.astro index b035024..374cf17 100644 --- a/src/pages/compare/vs-function-calling.astro +++ b/src/pages/compare/vs-function-calling.astro @@ -1,7 +1,7 @@ --- import SubpageLayout from '@layouts/SubpageLayout.astro'; -const _body = "
\n
\n
\n Compare\n /\n vs AI Function Calling\n
\n
Comparison
\n

Traverse vs AI Function Calling: Contracts vs Definitions

\n

Function calling gives AI agents a list of functions to invoke. Traverse gives agents contracts with preconditions, postconditions, enforcement, and trace artifacts. A meaningful difference when the function matters.

\n
\n
\n\n
\n\n \n\n
\n

What function calling solves

\n

\n Function calling lets LLMs invoke external tools. The model sees a list of function definitions, picks the right one, produces the arguments, and the calling code runs the function and returns the result.\n

\n

\n This works well for simple integrations: look up a user record, send a notification, query a search index. The model handles intent and argument construction. Your code handles execution.\n

\n

\n It is the foundation of most AI agent tooling today. It is well supported across OpenAI, Anthropic, Google, and the MCP ecosystem.\n

\n
\n\n
\n

Problems with function calling alone

\n

\n Function calling works. But when the function being called is a business capability with rules, preconditions, and compliance requirements, the bare function definition model has gaps.\n

\n\n
    \n
  • \n 01\n
    \n No preconditions\n A function signature says what parameters to pass. It does not say what must be true before calling. The agent learns about failures by calling the function and getting an error back — often after side effects have already started.\n
    \n
  • \n
  • \n 02\n
    \n No enforcement\n If the agent passes invalid inputs, the function decides what to do. Maybe it throws. Maybe it silently accepts them. Behavior is up to the implementation. The agent cannot verify correctness before calling.\n
    \n
  • \n
  • \n 03\n
    \n No audit trail\n You know a function was called. You may have a log entry. But you do not have a structured, queryable record of the inputs, outputs, which version ran, and whether all conditions were met. Compliance teams ask for exactly this.\n
    \n
  • \n
  • \n 04\n
    \n Definitions go stale\n Function definitions in a system prompt or tool list are text. When the underlying function changes, the definition may not be updated. Agents trained or prompted on stale definitions call capabilities that have changed or no longer exist.\n
    \n
  • \n
\n
\n\n
\n

What Traverse adds on top

\n

\n Traverse does not replace function calling. It governs the capabilities that function calling invokes. The agent still calls a function. That function is now backed by a contract and a runtime that enforces it.\n

\n\n
    \n
  • \n pre\n
    \n Preconditions\n The contract declares what must be true before the capability can run. The runtime checks this before execution. The agent can read the contract and know what is required before calling.\n
    \n
  • \n
  • \n post\n
    \n Postconditions\n The contract declares what the output will look like and what must be true after execution. The runtime validates the output before returning it. The agent can trust the output shape.\n
    \n
  • \n
  • \n run\n
    \n Runtime enforcement\n Validation happens at the runtime level, not inside the function. This is not a convention or a doc string. The capability cannot run if preconditions are unmet. Full stop.\n
    \n
  • \n
  • \n log\n
    \n Trace artifacts\n Every execution produces a structured trace: inputs, outputs, contract version, timestamp, and result. Queryable. Replayable. Ready for compliance review without extra instrumentation.\n
    \n
  • \n
  • \n ver\n
    \n Versioned contracts\n The capability registry always reflects what actually runs. Agents resolve capabilities by name and version. A stale definition is a contract mismatch the registry catches at load time, not at runtime surprise.\n
    \n
  • \n
\n
\n\n
\n

Side-by-side: raw function definition vs Traverse contract

\n

The same capability — checking promotion eligibility — defined two ways.

\n\n
\n
\n
\n Raw function definition (OpenAI tool format)\n
\n
// What the agent sees\n{\n \"name\": \"check_promo_eligibility\",\n \"description\": \"Check if a promo code\n is valid for a customer\",\n \"parameters\": {\n \"type\": \"object\",\n \"properties\": {\n \"customer_id\": { \"type\": \"string\" },\n \"promo_code\": { \"type\": \"string\" },\n \"cart_total\": { \"type\": \"number\" }\n },\n \"required\": [\"customer_id\", \"promo_code\"]\n }\n}\n\n// What happens if cart_total is missing?\n// What must be true about customer_id?\n// What does the response look like?\n// Which version of this logic ran?\n// Was it audited?\n// Nobody knows.\n
\n
\n\n
\n
\n Traverse contract\n
\n
[capability]\nname = \"promotions.check-eligibility\"\nversion = \"2.1.0\"\nplacement = [\"browser\", \"edge\", \"cloud\", \"ai-pipeline\"]\n\n[preconditions]\n# Enforced before execution. Cannot be bypassed.\ncustomer_id = \"non-empty string, max 64 chars\"\npromo_code = \"non-empty string, alphanumeric\"\ncart_total = \"float, >= 0.0\"\nregion = \"ISO 3166-1 alpha-2\"\n\n[postconditions]\n# Enforced after execution. Output shape guaranteed.\neligible = \"boolean\"\ndiscount_pct = \"float, 0.0..100.0 when eligible\"\nreason = \"string when !eligible\"\nexpires_at = \"RFC3339 timestamp\"\n\n[trace]\nemit = true\n# Trace includes: inputs, outputs, version, timestamp,\n# precondition results, postcondition results.\n
\n
\n
\n\n

\n The Traverse contract is not documentation. The runtime reads it and refuses to execute if any condition is unmet. The agent can load the contract and know exactly what is required before calling.\n

\n
\n\n
\n

Using them together via MCP

\n

\n Traverse and function calling are not mutually exclusive. You can expose Traverse capabilities as MCP tools. The agent calls them through standard function calling. The capabilities just come with contracts and traces attached.\n

\n\n
\n
\n
\n mcp-server/tools.ts\n
\n
\nimport { TraverseRuntime } from '@traverse-framework/runtime';\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\n\nconst runtime = await TraverseRuntime.init({ registry: process.env.REGISTRY_URL });\nconst server = new McpServer({ name: 'traverse-capabilities', version: '1.0.0' });\n\n// Expose Traverse capability as an MCP tool.\n// The agent calls it like any function. The runtime enforces the contract.\nserver.tool(\n 'check-promo-eligibility',\n 'Check promotion eligibility. Contract-enforced. Produces a trace.',\n {\n customer_id: z.string(),\n promo_code: z.string(),\n cart_total: z.number(),\n region: z.string(),\n },\n async ({ customer_id, promo_code, cart_total, region }) => {\n const result = await runtime.execute(\n 'promotions.check-eligibility@2.1.0',\n { customer_id, promo_code, cart_total, region }\n );\n\n // result.trace_id links this AI call to every other system\n // that ran this capability for the same transaction\n return {\n content: [{ type: 'text', text: JSON.stringify({\n ...result.output,\n trace_id: result.trace_id,\n })}],\n };\n }\n);\n
\n
\n\n
\n What the agent gets: the same function-calling interface it already knows. What your system gets: contract enforcement, versioned execution, and a trace that links every AI call to the same capability your browser and backend use.\n
\n
\n\n
\n

The verdict

\n

\n Use function calling to let AI agents invoke tools. Use Traverse to ensure the tools worth invoking have enforced contracts and produce auditable traces.\n

\n

\n Not every function needs a Traverse contract. A search tool, a calculator, a timezone lookup — raw function calling is fine. But pricing logic, eligibility checks, compliance validations? Those are capabilities worth governing. Traverse is built for exactly that.\n

\n

\n The two compose cleanly. Expose Traverse capabilities as MCP tools. Your agent gets function calling that happens to come with enforcement and traceability baked in.\n

\n
\n\n \n\n \n
\n
\n\n
\n
\n
\n
\n
Give your AI agents governed capabilities.
\n
Contract-enforced. Traceable. Versioned.
\n
\n \n
\n\n"; +const _body = "
\n
\n \n
Comparison
\n

Traverse vs AI Function Calling: Contracts vs Definitions

\n

Function calling gives AI agents a list of functions to invoke. Traverse gives agents contracts with preconditions, postconditions, enforcement, and trace artifacts. A meaningful difference when the function matters.

\n
\n
\n\n
\n\n \n\n
\n

What function calling solves

\n

\n Function calling lets LLMs invoke external tools. The model sees a list of function definitions, picks the right one, produces the arguments, and the calling code runs the function and returns the result.\n

\n

\n This works well for simple integrations: look up a user record, send a notification, query a search index. The model handles intent and argument construction. Your code handles execution.\n

\n

\n It is the foundation of most AI agent tooling today. It is well supported across OpenAI, Anthropic, Google, and the MCP ecosystem.\n

\n
\n\n
\n

Problems with function calling alone

\n

\n Function calling works. But when the function being called is a business capability with rules, preconditions, and compliance requirements, the bare function definition model has gaps.\n

\n\n
    \n
  • \n 01\n
    \n No preconditions\n A function signature says what parameters to pass. It does not say what must be true before calling. The agent learns about failures by calling the function and getting an error back — often after side effects have already started.\n
    \n
  • \n
  • \n 02\n
    \n No enforcement\n If the agent passes invalid inputs, the function decides what to do. Maybe it throws. Maybe it silently accepts them. Behavior is up to the implementation. The agent cannot verify correctness before calling.\n
    \n
  • \n
  • \n 03\n
    \n No audit trail\n You know a function was called. You may have a log entry. But you do not have a structured, queryable record of the inputs, outputs, which version ran, and whether all conditions were met. Compliance teams ask for exactly this.\n
    \n
  • \n
  • \n 04\n
    \n Definitions go stale\n Function definitions in a system prompt or tool list are text. When the underlying function changes, the definition may not be updated. Agents trained or prompted on stale definitions call capabilities that have changed or no longer exist.\n
    \n
  • \n
\n
\n\n
\n

What Traverse adds on top

\n

\n Traverse does not replace function calling. It governs the capabilities that function calling invokes. The agent still calls a function. That function is now backed by a contract and a runtime that enforces it.\n

\n\n
    \n
  • \n pre\n
    \n Preconditions\n The contract declares what must be true before the capability can run. The runtime checks this before execution. The agent can read the contract and know what is required before calling.\n
    \n
  • \n
  • \n post\n
    \n Postconditions\n The contract declares what the output will look like and what must be true after execution. The runtime validates the output before returning it. The agent can trust the output shape.\n
    \n
  • \n
  • \n run\n
    \n Runtime enforcement\n Validation happens at the runtime level, not inside the function. This is not a convention or a doc string. The capability cannot run if preconditions are unmet. Full stop.\n
    \n
  • \n
  • \n log\n
    \n Trace artifacts\n Every execution produces a structured trace: inputs, outputs, contract version, timestamp, and result. Queryable. Replayable. Ready for compliance review without extra instrumentation.\n
    \n
  • \n
  • \n ver\n
    \n Versioned contracts\n The capability registry always reflects what actually runs. Agents resolve capabilities by name and version. A stale definition is a contract mismatch the registry catches at load time, not at runtime surprise.\n
    \n
  • \n
\n
\n\n
\n

Side-by-side: raw function definition vs Traverse contract

\n

The same capability — checking promotion eligibility — defined two ways.

\n\n
\n
\n
\n Raw function definition (OpenAI tool format)\n
\n
// What the agent sees\n{\n \"name\": \"check_promo_eligibility\",\n \"description\": \"Check if a promo code\n is valid for a customer\",\n \"parameters\": {\n \"type\": \"object\",\n \"properties\": {\n \"customer_id\": { \"type\": \"string\" },\n \"promo_code\": { \"type\": \"string\" },\n \"cart_total\": { \"type\": \"number\" }\n },\n \"required\": [\"customer_id\", \"promo_code\"]\n }\n}\n\n// What happens if cart_total is missing?\n// What must be true about customer_id?\n// What does the response look like?\n// Which version of this logic ran?\n// Was it audited?\n// Nobody knows.\n
\n
\n\n
\n
\n Traverse contract\n
\n
[capability]\nname = \"promotions.check-eligibility\"\nversion = \"2.1.0\"\nplacement = [\"browser\", \"edge\", \"cloud\", \"ai-pipeline\"]\n\n[preconditions]\n# Enforced before execution. Cannot be bypassed.\ncustomer_id = \"non-empty string, max 64 chars\"\npromo_code = \"non-empty string, alphanumeric\"\ncart_total = \"float, >= 0.0\"\nregion = \"ISO 3166-1 alpha-2\"\n\n[postconditions]\n# Enforced after execution. Output shape guaranteed.\neligible = \"boolean\"\ndiscount_pct = \"float, 0.0..100.0 when eligible\"\nreason = \"string when !eligible\"\nexpires_at = \"RFC3339 timestamp\"\n\n[trace]\nemit = true\n# Trace includes: inputs, outputs, version, timestamp,\n# precondition results, postcondition results.\n
\n
\n
\n\n

\n The Traverse contract is not documentation. The runtime reads it and refuses to execute if any condition is unmet. The agent can load the contract and know exactly what is required before calling.\n

\n
\n\n
\n

Using them together via MCP

\n

\n Traverse and function calling are not mutually exclusive. You can expose Traverse capabilities as MCP tools. The agent calls them through standard function calling. The capabilities just come with contracts and traces attached.\n

\n\n
\n
\n
\n mcp-server/tools.ts\n
\n
\nimport { TraverseRuntime } from '@traverse-framework/runtime';\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\n\nconst runtime = await TraverseRuntime.init({ registry: process.env.REGISTRY_URL });\nconst server = new McpServer({ name: 'traverse-capabilities', version: '1.0.0' });\n\n// Expose Traverse capability as an MCP tool.\n// The agent calls it like any function. The runtime enforces the contract.\nserver.tool(\n 'check-promo-eligibility',\n 'Check promotion eligibility. Contract-enforced. Produces a trace.',\n {\n customer_id: z.string(),\n promo_code: z.string(),\n cart_total: z.number(),\n region: z.string(),\n },\n async ({ customer_id, promo_code, cart_total, region }) => {\n const result = await runtime.execute(\n 'promotions.check-eligibility@2.1.0',\n { customer_id, promo_code, cart_total, region }\n );\n\n // result.trace_id links this AI call to every other system\n // that ran this capability for the same transaction\n return {\n content: [{ type: 'text', text: JSON.stringify({\n ...result.output,\n trace_id: result.trace_id,\n })}],\n };\n }\n);\n
\n
\n\n
\n What the agent gets: the same function-calling interface it already knows. What your system gets: contract enforcement, versioned execution, and a trace that links every AI call to the same capability your browser and backend use.\n
\n
\n\n
\n

The verdict

\n

\n Use function calling to let AI agents invoke tools. Use Traverse to ensure the tools worth invoking have enforced contracts and produce auditable traces.\n

\n

\n Not every function needs a Traverse contract. A search tool, a calculator, a timezone lookup — raw function calling is fine. But pricing logic, eligibility checks, compliance validations? Those are capabilities worth governing. Traverse is built for exactly that.\n

\n

\n The two compose cleanly. Expose Traverse capabilities as MCP tools. Your agent gets function calling that happens to come with enforcement and traceability baked in.\n

\n
\n\n \n\n \n
\n
\n\n
\n
\n
\n
\n
Give your AI agents governed capabilities.
\n
Contract-enforced. Traceable. Versioned.
\n
\n \n
\n\n"; --- \n
\n canonical={"https://traverse-framework.com/compare/vs-function-calling.html"} crumbs={[{ label: "Home", href: "/" }, { label: "Compare", href: "/compare/" }]} > + diff --git a/src/pages/compare/vs-microservices.astro b/src/pages/compare/vs-microservices.astro index a84674f..3ef5018 100644 --- a/src/pages/compare/vs-microservices.astro +++ b/src/pages/compare/vs-microservices.astro @@ -1,7 +1,7 @@ --- import SubpageLayout from '@layouts/SubpageLayout.astro'; -const _body = "
\n
\n
\n Compare\n /\n vs Microservices\n
\n
Comparison
\n

Traverse vs Microservices: What is the Difference?

\n

Traverse is not a replacement for microservices. It solves a specific problem microservices do not: portable, contract-governed business logic that runs identically across environments.

\n
\n
\n\n
\n\n \n\n
\n

What microservices solve

\n

\n Microservices decompose large systems into independently deployable services. Each service owns its domain, can be scaled independently, and can be built by a separate team in a separate language.\n

\n

\n This is genuinely useful. A monolith that grew too large, a team that needs to ship without coordinating with six other teams, a service that needs 10x the capacity of everything else. Microservices handle these cases well.\n

\n

\n The pattern is well understood, well tooled, and battle-tested. It is not going anywhere.\n

\n
\n\n
\n

What Traverse solves

\n

\n Traverse solves a different problem. Imagine a pricing rule. It needs to run in the browser for instant feedback. It needs to run at the edge for fast confirmation. It needs to run in a cloud worker for fulfillment. It needs to run in an AI pipeline that handles quotes.\n

\n

\n Four runtimes, one rule. Without Traverse, each environment reimplements the rule. They drift. A bug gets fixed in the cloud but not the browser. An eligibility change ships to the API but not the AI pipeline. The rule you thought was consistent is actually four different versions of the same idea.\n

\n

\n Traverse compiles that rule to a single WASM binary with a machine-readable contract. Every environment loads the same binary. The contract is enforced before every execution. A trace artifact is produced every time.\n

\n
\n The core difference: microservices are about where services run and how they communicate. Traverse is about what a specific piece of logic does and that it behaves identically everywhere.\n
\n
\n\n
\n

Key differences

\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
DimensionMicroservicesTraverse
Unit of deploymentA service with an endpoint, a container, an APIA governed WASM binary with a contract
CommunicationOver the network: HTTP, gRPC, message queuesIn-process: no network hop, runs where the caller runs
ContractsImplicit: API docs, OpenAPI specs, informal agreementsMachine-readable, enforced before every execution
Execution tracesNot produced by default. Requires logging or tracing setup.Produced for every execution, structured and queryable
PortabilityServices run in specific environments, typically containerizedSame binary in browser, edge, cloud, and AI pipeline
Primary concernSystem decomposition, independent scaling, team autonomyConsistent, governed business logic across environments
\n
\n\n
\n

When to use which

\n
\n
\n

Use microservices when

\n
    \n
  • You need to decompose a large system into independently scalable parts
  • \n
  • Multiple teams need to own separate domains without coordination overhead
  • \n
  • You need different services to use different technology stacks
  • \n
  • Independent deployment cadences matter per service
  • \n
\n
\n
\n

Use Traverse when

\n
    \n
  • A business rule needs to run identically in multiple environments
  • \n
  • You need enforced contracts and audit trails on business logic
  • \n
  • Logic drift between environments is causing bugs or compliance issues
  • \n
  • An AI pipeline needs to call the same logic your backend already uses
  • \n
\n
\n
\n
\n They compose. Your microservice can use Traverse internally to run business capabilities. The service stays independently deployable. The logic inside it stays governed, portable, and traceable.\n
\n
\n\n
\n

Calling a Traverse capability from a microservice

\n

\n This is what the integration looks like in practice. A pricing microservice uses Traverse to execute the pricing logic. The logic is identical to what runs in the browser and in the AI pipeline.\n

\n\n
\n
\n
\n pricing-service/src/handler.rs\n
\n
\n// Traverse runtime loaded once at service startup\nlet runtime = TraverseRuntime::new(config).await?;\n\n// Capability loaded from the registry — same binary as the browser uses\nlet capability = runtime\n .load(\"pricing.calculate-order-total@1.3.2\")\n .await?;\n\n// Handler: Traverse validates preconditions before execution\nasync fn handle_quote_request(\n runtime: &TraverseRuntime,\n capability: &Capability,\n order: Order,\n) -> Result<QuoteResponse> {\n let input = json!({\n \"items\": order.items,\n \"customer_tier\": order.customer_tier,\n \"promo_code\": order.promo_code,\n \"currency\": order.currency,\n });\n\n // Runtime checks preconditions, runs WASM, checks postconditions\n let result = runtime.execute(capability, input).await?;\n\n // trace_id links this execution to the browser quote and AI pipeline run\n tracing::info(trace_id = %result.trace_id, \"pricing executed\");\n\n Ok(QuoteResponse {\n total: result.output[\"total\"].as_f64()?,\n breakdown: result.output[\"breakdown\"].clone(),\n trace_id: result.trace_id,\n })\n}\n
\n
\n\n

\n The pricing service owns its API surface, its deployment pipeline, and its scaling. Traverse owns the pricing logic. Neither intrudes on the other.\n

\n
\n\n
\n

The verdict

\n

\n If you run microservices, Traverse is additive. Pick one service where logic drift between environments is causing the most pain. Replace that logic with a Traverse capability. The service stays a microservice. The logic becomes governed.\n

\n

\n If you are starting fresh and deciding on architecture, use microservices for system decomposition. Use Traverse for business logic that will need to run in more than one kind of environment.\n

\n

\n They are good at different things. Both is often the right answer.\n

\n
\n\n \n\n \n
\n
\n\n
\n
\n
\n
\n
Try it alongside your existing services.
\n
Add a single capability. See a trace. Decide from there.
\n
\n \n
\n\n"; +const _body = "
\n
\n \n
Comparison
\n

Traverse vs Microservices: What is the Difference?

\n

Traverse is not a replacement for microservices. It solves a specific problem microservices do not: portable, contract-governed business logic that runs identically across environments.

\n
\n
\n\n
\n\n \n\n
\n

What microservices solve

\n

\n Microservices decompose large systems into independently deployable services. Each service owns its domain, can be scaled independently, and can be built by a separate team in a separate language.\n

\n

\n This is genuinely useful. A monolith that grew too large, a team that needs to ship without coordinating with six other teams, a service that needs 10x the capacity of everything else. Microservices handle these cases well.\n

\n

\n The pattern is well understood, well tooled, and battle-tested. It is not going anywhere.\n

\n
\n\n
\n

What Traverse solves

\n

\n Traverse solves a different problem. Imagine a pricing rule. It needs to run in the browser for instant feedback. It needs to run at the edge for fast confirmation. It needs to run in a cloud worker for fulfillment. It needs to run in an AI pipeline that handles quotes.\n

\n

\n Four runtimes, one rule. Without Traverse, each environment reimplements the rule. They drift. A bug gets fixed in the cloud but not the browser. An eligibility change ships to the API but not the AI pipeline. The rule you thought was consistent is actually four different versions of the same idea.\n

\n

\n Traverse compiles that rule to a single WASM binary with a machine-readable contract. Every environment loads the same binary. The contract is enforced before every execution. A trace artifact is produced every time.\n

\n
\n The core difference: microservices are about where services run and how they communicate. Traverse is about what a specific piece of logic does and that it behaves identically everywhere.\n
\n
\n\n
\n

Key differences

\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
DimensionMicroservicesTraverse
Unit of deploymentA service with an endpoint, a container, an APIA governed WASM binary with a contract
CommunicationOver the network: HTTP, gRPC, message queuesIn-process: no network hop, runs where the caller runs
ContractsImplicit: API docs, OpenAPI specs, informal agreementsMachine-readable, enforced before every execution
Execution tracesNot produced by default. Requires logging or tracing setup.Produced for every execution, structured and queryable
PortabilityServices run in specific environments, typically containerizedSame binary in browser, edge, cloud, and AI pipeline
Primary concernSystem decomposition, independent scaling, team autonomyConsistent, governed business logic across environments
\n
\n\n
\n

When to use which

\n
\n
\n

Use microservices when

\n
    \n
  • You need to decompose a large system into independently scalable parts
  • \n
  • Multiple teams need to own separate domains without coordination overhead
  • \n
  • You need different services to use different technology stacks
  • \n
  • Independent deployment cadences matter per service
  • \n
\n
\n
\n

Use Traverse when

\n
    \n
  • A business rule needs to run identically in multiple environments
  • \n
  • You need enforced contracts and audit trails on business logic
  • \n
  • Logic drift between environments is causing bugs or compliance issues
  • \n
  • An AI pipeline needs to call the same logic your backend already uses
  • \n
\n
\n
\n
\n They compose. Your microservice can use Traverse internally to run business capabilities. The service stays independently deployable. The logic inside it stays governed, portable, and traceable.\n
\n
\n\n
\n

Calling a Traverse capability from a microservice

\n

\n This is what the integration looks like in practice. A pricing microservice uses Traverse to execute the pricing logic. The logic is identical to what runs in the browser and in the AI pipeline.\n

\n\n
\n
\n
\n pricing-service/src/handler.rs\n
\n
\n// Traverse runtime loaded once at service startup\nlet runtime = TraverseRuntime::new(config).await?;\n\n// Capability loaded from the registry — same binary as the browser uses\nlet capability = runtime\n .load(\"pricing.calculate-order-total@1.3.2\")\n .await?;\n\n// Handler: Traverse validates preconditions before execution\nasync fn handle_quote_request(\n runtime: &TraverseRuntime,\n capability: &Capability,\n order: Order,\n) -> Result<QuoteResponse> {\n let input = json!({\n \"items\": order.items,\n \"customer_tier\": order.customer_tier,\n \"promo_code\": order.promo_code,\n \"currency\": order.currency,\n });\n\n // Runtime checks preconditions, runs WASM, checks postconditions\n let result = runtime.execute(capability, input).await?;\n\n // trace_id links this execution to the browser quote and AI pipeline run\n tracing::info(trace_id = %result.trace_id, \"pricing executed\");\n\n Ok(QuoteResponse {\n total: result.output[\"total\"].as_f64()?,\n breakdown: result.output[\"breakdown\"].clone(),\n trace_id: result.trace_id,\n })\n}\n
\n
\n\n

\n The pricing service owns its API surface, its deployment pipeline, and its scaling. Traverse owns the pricing logic. Neither intrudes on the other.\n

\n
\n\n
\n

The verdict

\n

\n If you run microservices, Traverse is additive. Pick one service where logic drift between environments is causing the most pain. Replace that logic with a Traverse capability. The service stays a microservice. The logic becomes governed.\n

\n

\n If you are starting fresh and deciding on architecture, use microservices for system decomposition. Use Traverse for business logic that will need to run in more than one kind of environment.\n

\n

\n They are good at different things. Both is often the right answer.\n

\n
\n\n \n\n \n
\n\n\n
\n
\n
\n
\n
Try it alongside your existing services.
\n
Add a single capability. See a trace. Decide from there.
\n
\n \n
\n\n"; --- \n
\n canonical={"https://traverse-framework.com/compare/vs-microservices.html"} crumbs={[{ label: "Home", href: "/" }, { label: "Compare", href: "/compare/" }]} > + diff --git a/src/pages/compare/vs-serverless.astro b/src/pages/compare/vs-serverless.astro index 917a3d5..9149d04 100644 --- a/src/pages/compare/vs-serverless.astro +++ b/src/pages/compare/vs-serverless.astro @@ -1,7 +1,7 @@ --- import SubpageLayout from '@layouts/SubpageLayout.astro'; -const _body = "
\n
\n
\n Compare\n /\n vs Serverless\n
\n
Comparison
\n

Traverse vs Serverless Functions: Different Problems

\n

Serverless functions handle event-driven compute at scale. Traverse handles portable, contract-governed business logic. They solve different problems and are often used together.

\n
\n
\n\n
\n\n \n\n
\n

What serverless solves

\n

\n Serverless functions handle event-driven, stateless compute that scales to zero. You pay per invocation. You do not manage servers. Scaling is automatic. Cold starts exist, but for many workloads they are acceptable.\n

\n

\n Serverless is genuinely good at certain things: processing webhook events, handling async jobs, running lightweight APIs, processing file uploads, and any workload where traffic is bursty and unpredictable.\n

\n

\n It is a well-understood pattern with solid tooling across AWS Lambda, Cloudflare Workers, Vercel Functions, and Deno Deploy.\n

\n
\n\n
\n

What Traverse solves

\n

\n Traverse solves a narrower problem. A business rule needs to run in multiple places. An eligibility check runs in the browser, at the edge, in a cloud function, and in an AI pipeline. Each environment is different. Each one needs the same result.\n

\n

\n Without governance, that rule gets copied, adapted, and then it diverges. The browser version gets a bug fix the cloud version does not. The AI pipeline gets a different interpretation of the same spec.\n

\n

\n Traverse compiles the rule to a WASM binary with a machine-readable contract. The runtime validates preconditions before execution and postconditions after. Every execution produces a structured trace artifact. The same binary runs in every environment.\n

\n
\n The distinction: serverless is about how compute is provisioned and priced. Traverse is about whether a specific piece of business logic is consistent, governed, and auditable wherever it runs.\n
\n
\n\n
\n

Key differences

\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
DimensionServerless FunctionsTraverse
Execution modelInvoked over the network, scales to zero, managed by the platformRuns in-process as WASM, no network hop, no cold start for the capability itself
Environment specificityFunctions are tied to a platform (Lambda, Workers, etc.)Same binary runs across browser, edge, cloud, and AI pipeline
Contract systemNone built in. You define the interface yourself, informally.Machine-readable contracts enforced before every execution
Execution tracesNot produced by default. CloudWatch logs, custom telemetry, or nothing.Structured trace artifact on every execution, queryable
VersioningFunction aliases and versions vary by platform. Often informal.Capability registry with pinned versions, contract versioning
Primary useEvent-driven async processing, webhooks, lightweight APIsPortable governed business logic across environments
\n
\n\n
\n

When to use which

\n
\n
\n

Use serverless when

\n
    \n
  • You have bursty, unpredictable traffic that needs to scale to zero
  • \n
  • Processing webhook events, async jobs, or file uploads
  • \n
  • You want zero server management overhead
  • \n
  • Per-invocation billing fits your cost model
  • \n
  • The function does not need to run in a browser or AI pipeline
  • \n
\n
\n
\n

Use Traverse when

\n
    \n
  • A business rule needs to produce the same result in multiple environments
  • \n
  • Compliance requires a reproducible, auditable execution record
  • \n
  • Logic drift between environments is causing production bugs
  • \n
  • An AI agent needs to call the same business logic your backend uses
  • \n
  • You want contracts enforced before execution, not just hoped for
  • \n
\n
\n
\n
\n\n
\n

Running Traverse inside a serverless function

\n

\n These tools compose cleanly. A serverless function handles the event-driven invocation and scaling. Traverse handles the business logic inside that function. The function stays stateless. The logic stays governed.\n

\n\n
\n
\n
\n functions/process-order.ts\n
\n
\n// Cloudflare Worker — serverless, scales to zero\nimport { TraverseRuntime } from '@traverse-framework/runtime';\n\n// Runtime initialized once at worker startup (not per-request)\nconst runtime = await TraverseRuntime.init({\n registry: Env.TRAVERSE_REGISTRY_URL,\n});\n\nexport default {\n async fetch(request: Request, env: Env): Promise<Response> {\n const order = await request.json();\n\n // Business logic: same WASM binary as the storefront and AI pipeline\n const eligibility = await runtime.execute(\n 'promotions.check-eligibility@2.1.0',\n {\n customer_id: order.customer_id,\n promo_code: order.promo_code,\n cart_total: order.cart_total,\n region: order.region,\n }\n );\n\n // Contract enforced. Trace produced. No extra setup needed.\n if (!eligibility.output.eligible) {\n return Response.json(\n { error: eligibility.output.reason, trace_id: eligibility.trace_id },\n { status: 422 }\n );\n }\n\n return Response.json({ applied: true, trace_id: eligibility.trace_id });\n },\n};\n
\n
\n\n

\n The Worker scales to zero between invocations. The eligibility logic runs identically in the browser, in this Worker, and in any AI pipeline that calls it. Same contract. Same trace format. Same result.\n

\n
\n\n
\n

The verdict

\n

\n Serverless is about how and where compute runs. Traverse is about what that compute does and whether it is consistent. Choosing one does not mean avoiding the other.\n

\n

\n If you run serverless functions that execute business logic, Traverse can govern that logic inside the function. You get the scaling and zero-management benefits of serverless, and the contract enforcement and traceability of Traverse.\n

\n

\n If your serverless function is doing pure infrastructure work (S3 events, webhook acknowledgment, background jobs), you may not need Traverse at all. Pick the tool that matches the job.\n

\n
\n\n \n\n \n
\n\n\n
\n
\n
\n
\n
Add governance to your existing functions.
\n
Drop a Traverse capability into a function you already run.
\n
\n \n
\n\n"; +const _body = "
\n
\n \n
Comparison
\n

Traverse vs Serverless Functions: Different Problems

\n

Serverless functions handle event-driven compute at scale. Traverse handles portable, contract-governed business logic. They solve different problems and are often used together.

\n
\n
\n\n
\n\n \n\n
\n

What serverless solves

\n

\n Serverless functions handle event-driven, stateless compute that scales to zero. You pay per invocation. You do not manage servers. Scaling is automatic. Cold starts exist, but for many workloads they are acceptable.\n

\n

\n Serverless is genuinely good at certain things: processing webhook events, handling async jobs, running lightweight APIs, processing file uploads, and any workload where traffic is bursty and unpredictable.\n

\n

\n It is a well-understood pattern with solid tooling across AWS Lambda, Cloudflare Workers, Vercel Functions, and Deno Deploy.\n

\n
\n\n
\n

What Traverse solves

\n

\n Traverse solves a narrower problem. A business rule needs to run in multiple places. An eligibility check runs in the browser, at the edge, in a cloud function, and in an AI pipeline. Each environment is different. Each one needs the same result.\n

\n

\n Without governance, that rule gets copied, adapted, and then it diverges. The browser version gets a bug fix the cloud version does not. The AI pipeline gets a different interpretation of the same spec.\n

\n

\n Traverse compiles the rule to a WASM binary with a machine-readable contract. The runtime validates preconditions before execution and postconditions after. Every execution produces a structured trace artifact. The same binary runs in every environment.\n

\n
\n The distinction: serverless is about how compute is provisioned and priced. Traverse is about whether a specific piece of business logic is consistent, governed, and auditable wherever it runs.\n
\n
\n\n
\n

Key differences

\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
DimensionServerless FunctionsTraverse
Execution modelInvoked over the network, scales to zero, managed by the platformRuns in-process as WASM, no network hop, no cold start for the capability itself
Environment specificityFunctions are tied to a platform (Lambda, Workers, etc.)Same binary runs across browser, edge, cloud, and AI pipeline
Contract systemNone built in. You define the interface yourself, informally.Machine-readable contracts enforced before every execution
Execution tracesNot produced by default. CloudWatch logs, custom telemetry, or nothing.Structured trace artifact on every execution, queryable
VersioningFunction aliases and versions vary by platform. Often informal.Capability registry with pinned versions, contract versioning
Primary useEvent-driven async processing, webhooks, lightweight APIsPortable governed business logic across environments
\n
\n\n
\n

When to use which

\n
\n
\n

Use serverless when

\n
    \n
  • You have bursty, unpredictable traffic that needs to scale to zero
  • \n
  • Processing webhook events, async jobs, or file uploads
  • \n
  • You want zero server management overhead
  • \n
  • Per-invocation billing fits your cost model
  • \n
  • The function does not need to run in a browser or AI pipeline
  • \n
\n
\n
\n

Use Traverse when

\n
    \n
  • A business rule needs to produce the same result in multiple environments
  • \n
  • Compliance requires a reproducible, auditable execution record
  • \n
  • Logic drift between environments is causing production bugs
  • \n
  • An AI agent needs to call the same business logic your backend uses
  • \n
  • You want contracts enforced before execution, not just hoped for
  • \n
\n
\n
\n
\n\n
\n

Running Traverse inside a serverless function

\n

\n These tools compose cleanly. A serverless function handles the event-driven invocation and scaling. Traverse handles the business logic inside that function. The function stays stateless. The logic stays governed.\n

\n\n
\n
\n
\n functions/process-order.ts\n
\n
\n// Cloudflare Worker — serverless, scales to zero\nimport { TraverseRuntime } from '@traverse-framework/runtime';\n\n// Runtime initialized once at worker startup (not per-request)\nconst runtime = await TraverseRuntime.init({\n registry: Env.TRAVERSE_REGISTRY_URL,\n});\n\nexport default {\n async fetch(request: Request, env: Env): Promise<Response> {\n const order = await request.json();\n\n // Business logic: same WASM binary as the storefront and AI pipeline\n const eligibility = await runtime.execute(\n 'promotions.check-eligibility@2.1.0',\n {\n customer_id: order.customer_id,\n promo_code: order.promo_code,\n cart_total: order.cart_total,\n region: order.region,\n }\n );\n\n // Contract enforced. Trace produced. No extra setup needed.\n if (!eligibility.output.eligible) {\n return Response.json(\n { error: eligibility.output.reason, trace_id: eligibility.trace_id },\n { status: 422 }\n );\n }\n\n return Response.json({ applied: true, trace_id: eligibility.trace_id });\n },\n};\n
\n
\n\n

\n The Worker scales to zero between invocations. The eligibility logic runs identically in the browser, in this Worker, and in any AI pipeline that calls it. Same contract. Same trace format. Same result.\n

\n
\n\n
\n

The verdict

\n

\n Serverless is about how and where compute runs. Traverse is about what that compute does and whether it is consistent. Choosing one does not mean avoiding the other.\n

\n

\n If you run serverless functions that execute business logic, Traverse can govern that logic inside the function. You get the scaling and zero-management benefits of serverless, and the contract enforcement and traceability of Traverse.\n

\n

\n If your serverless function is doing pure infrastructure work (S3 events, webhook acknowledgment, background jobs), you may not need Traverse at all. Pick the tool that matches the job.\n

\n
\n\n \n\n \n \n\n\n
\n
\n
\n
\n
Add governance to your existing functions.
\n
Drop a Traverse capability into a function you already run.
\n
\n \n \n\n
"; --- \n
\n canonical={"https://traverse-framework.com/compare/vs-serverless.html"} crumbs={[{ label: "Home", href: "/" }, { label: "Compare", href: "/compare/" }]} > + diff --git a/src/pages/docs/architecture.astro b/src/pages/docs/architecture.astro index 8b8c91f..a8445d2 100644 --- a/src/pages/docs/architecture.astro +++ b/src/pages/docs/architecture.astro @@ -9,5 +9,29 @@ const _body = "
\n