Skip to content

Repository files navigation

Foundry SDK

enter image description here

@labsfoundry/sdk is a strict TypeScript SDK for converting product requirements into validated, machine-readable software architecture plans. It combines provider-backed design generation with deterministic validation and diagram generation.

Node.js 20+

TypeScript strict

License MIT

Keep provider API keys on trusted servers. Never expose OpenAI or external API credentials in browser bundles.

Contents

Capabilities

Capability Provider Call Deterministic Browser-Safe Core
Generate a system design Yes No No
Refine an existing design Yes No No
Compare designs Yes No No
Estimate complexity and cost ranges Yes No No
Validate design structure and quality No Yes Yes
Generate Mermaid or JSON diagrams No Yes Yes
Validate provider output with Zod No additional call Yes Yes
Query an optional technology catalog External HTTP No Native fetch

All provider results cross a Zod validation boundary before being returned. The default OpenAI provider requests structured output and then validates the parsed result again locally.

Architecture

flowchart LR

App["Server application"] --> Client["Foundry client"]

Client --> Systems["systems API"]

Client --> Diagrams["diagrams API"]

Client --> Registry["provider registry"]

  

Systems --> Input["Zod input validation"]

Input --> AI["AIProvider"]

AI --> OpenAI["OpenAIProvider"]

AI --> Custom["Custom provider"]

OpenAI --> Structured["Structured provider response"]

Custom --> Structured

Structured --> Output["Zod output validation"]

Output --> Design["SystemDesign"]

  

Design --> Validator["Deterministic validator"]

Design --> Diagrams

Validator --> Report["Validation report"]

Diagrams --> Mermaid["Mermaid text"]

Diagrams --> JSON["JSON graph"]

  

Registry -. optional .-> Tech["TechnologyDataProvider"]

Tech --> Catalog["External technology catalog"]

Loading

Generation request flow

sequenceDiagram

participant App as Application

participant SDK as Foundry

participant Schema as Zod

participant Retry as Retry/timeout layer

participant Provider as AIProvider

  

App->>SDK: systems.generate(input, options)

SDK->>Schema: validate GenerateSystemInput

alt invalid input

Schema-->>App: ValidationError

else valid input

SDK->>Retry: execute bounded request

Retry->>Provider: generateSystemDesign

Provider-->>Retry: structured response

Retry-->>SDK: provider result

SDK->>Schema: validate SystemDesign

alt malformed output

Schema-->>App: validation failure

else valid output

SDK-->>App: SystemDesign

end

end

Loading

Installation

Requirements:

  • Node.js 20 or newer

  • A server runtime for the default OpenAI provider

  • An OpenAI API key, or a custom AIProvider

npm  install  @labsfoundry/sdk

The package publishes ESM, CommonJS, declarations, and source maps:

import  { Foundry }  from  "@labsfoundry/sdk";
const { Foundry } = require("@labsfoundry/sdk");

Quick start

import  { Foundry }  from  "@labsfoundry/sdk";

  

const  foundry = new  Foundry({

apiKey: process.env.OPENAI_API_KEY!,

model: process.env.OPENAI_MODEL  ??  "gpt-5-mini",

});

  

const  design = await  foundry.systems.generate({

name:  "Multiplayer Survival Game",

description:

"A multiplayer survival game supporting 200 concurrent players with voice chat, inventory, authentication, analytics, and Solana payments.",

requirements: ["Players can join persistent worlds", "Payments must be auditable"],

constraints: {

concurrentUsers:  200,

regions: ["us-east", "eu-west"],

budget:  "medium",

teamSize:  6,

availabilityTarget:  99.9,

latencyTargetMs:  150,

},

preferences: {

languages: ["TypeScript"],

cloudProviders: ["AWS"],

avoid: ["self-managed Kubernetes"],

},

});

  

const  validation = foundry.systems.validate(design);

const  mermaid = foundry.diagrams.generate(design, {

format:  "mermaid",

type:  "architecture",

});

  

console.log({ design, validation, mermaid });

The library does not read environment variables automatically. Applications explicitly pass configuration, which keeps environment handling under application control.

OPENAI_API_KEY=

OPENAI_MODEL=gpt-5-mini

OPENAI_BASE_URL=

FOUNDRY_TECH_API_URL=

FOUNDRY_TECH_API_KEY=

Configuration

interface  FoundryConfig {

apiKey?: string;

model?: string;

provider?: AIProvider;

technologyDataProvider?: TechnologyDataProvider;

timeoutMs?: number;

maxRetries?: number;

baseUrl?: string;

logger?: Logger;

userAgent?: string;

}

Configuration

Option Type Default Notes
apiKey string Required unless provider is supplied
model string gpt-5-mini Model used by OpenAIProvider
provider AIProvider OpenAIProvider Replaces the default AI provider
technologyDataProvider TechnologyDataProvider Exposed through foundry.providers.technology
timeoutMs number 30000 Default timeout for each provider call
maxRetries number 2 Retry attempts after the initial request
baseUrl string OpenAI default Useful with compatible API gateways
logger Logger Silent Must not log sensitive payloads
userAgent string Provider default Optional HTTP user-agent value

Configuration is checked synchronously. Construction fails if credentials and a custom provider are both absent, if timeoutMs <= 0, or if maxRetries is not a non-negative integer.

const  foundry = new  Foundry({

provider:  new  InternalArchitectureProvider(),

timeoutMs:  45_000,

maxRetries:  3,

});

API reference

systems.generate(input, options?)

Generates and validates a complete design.

interface  GenerateSystemInput {

name: string;

description: string;

requirements?: string[];

constraints?: SystemConstraints;

preferences?: TechnologyPreferences;

context?: Record<string, unknown>;

}

Key input limits include a 200-character name, a description between 10 and 50,000 characters, bounded lists, and a maximum serialized provider prompt size of 500,000 characters.

const  design: SystemDesign = await  foundry.systems.generate(input, {

timeoutMs:  60_000,

signal: abortController.signal,

});

systems.refine(input, options?)

Requests structural changes while preserving the SystemDesign contract.

const  result = await  foundry.systems.refine({

design,

instruction:  "Reduce infrastructure cost and replace Kubernetes with managed containers.",

});

  

// result.design: SystemDesign

// result.changes: Array<{ path; description; reason }>

The instruction must contain 1–20,000 characters. The source design and refined result are validated.

systems.validate(design)

Runs synchronously without credentials, network access, or an AI request.

const  result = foundry.systems.validate(design);

  

if (!result.valid) {

for (const  issue  of result.errors) {

console.error(issue.code, issue.path, issue.message);

}

}

Returns:

interface  SystemValidationResult {

valid: boolean;

score: number; // 0–100

errors: ValidationIssue[];

warnings: ValidationIssue[];

suggestions: ValidationIssue[];

}

systems.compare(input, options?)

Compares 2–10 validated designs. Criteria scores use a 0–100 scale.

const  comparison = await  foundry.systems.compare({

designs: [designA, designB],

priorities: ["cost", "scalability", "developer experience"],

});

recommendedDesignId is nullable when the evidence does not support a clear winner.

systems.estimate(input, options?)

Returns directional ranges for team size, implementation time, and monthly infrastructure cost, plus complexity, operational burden, cost drivers, assumptions, confidence, and a mandatory disclaimer.

const  estimate = await  foundry.systems.estimate({ design });

  

console.log(estimate.estimatedTimelineWeeks.min);

console.log(estimate.infrastructureCostMonthlyUsd.max);

Estimates are engineering planning aids, not quotes or financial guarantees.

diagrams.generate(design, options)

Overloads preserve the output type:

const  source: string = foundry.diagrams.generate(design, {

format:  "mermaid",

type:  "data-flow",

});

  

const  graph: JsonDiagram = foundry.diagrams.generate(design, {

format:  "json",

type:  "architecture",

});

Supported types: architecture, sequence, deployment, data-flow, and entity-relationship.

SystemDesign model

classDiagram

class SystemDesign {

string id

string name

string summary

string architectureStyle

string[] assumptions

}

class SystemComponent {

string id

string[] responsibilities

string[] dependencies

string[] failureHandling

string scalingStrategy

}

class DatabaseRecommendation {

string ownerComponentId

string purpose

string backupStrategy

Entity[] entities

}

class ApiDefinition {

string componentId

boolean protected

object requestSchema

object responseSchema

}

class DataFlow {

string sourceComponentId

string targetComponentId

string protocol

}

class ArchitectureDiagram {

Node[] nodes

Edge[] edges

}

  

SystemDesign "1" *-- "many" SystemComponent

SystemDesign "1" *-- "many" DatabaseRecommendation

SystemDesign "1" *-- "many" ApiDefinition

SystemDesign "1" *-- "many" DataFlow

SystemDesign "1" *-- "many" ArchitectureDiagram

SystemComponent "1" <-- "many" DatabaseRecommendation : owner

SystemComponent "1" <-- "many" ApiDefinition : serves

Loading

Top-Level Sections

Section Purpose
requirements Functional and non-functional requirements
technologyStack Purpose, rationale, alternatives, and risks
components Responsibilities, dependencies, failure handling, and scaling
databases Ownership, entities, consistency, backups, and retention
apis Protocols, endpoints, authentication, schemas, and errors
dataFlows Sources, targets, data, protocols, security, and failures
infrastructure Providers, regions, targets, compute, storage, and disaster recovery
deployment Environments, CI/CD, releases, and rollback
security Authentication, authorization, encryption, secrets, and threats
scalability Scaling, caching, partitioning, bottlenecks, and triggers
observability Logs, metrics, traces, alerts, dashboards, and SLOs
risks and tradeoffs Explicit uncertainty and architectural decisions
implementationPhases Ordered goals, deliverables, duration ranges, and risks
metadata Timestamp, model, provider, and SDK version

All public schemas are exported, so persistence and API layers can reuse the same contracts:

import  { SystemDesignSchema, type SystemDesign }  from  "@labsfoundry/sdk";

  

const  design: SystemDesign = SystemDesignSchema.parse(untrustedJson);

Deterministic validation

flowchart TD

Start["Unknown input"] --> Schema{"SystemDesign schema valid?"}

Schema -- No --> SchemaErrors["Schema errors with paths"]

Schema -- Yes --> Graph["Build component dependency graph"]

Graph --> References["Check component, API, DB, and flow references"]

References --> Cycles["Detect circular dependencies"]

Cycles --> Quality["Check security, backup, scaling, failures, observability"]

Quality --> Score["Calculate quality score"]

SchemaErrors --> Result["SystemValidationResult"]

Score --> Result

Loading

Validation covers:

  • missing components and responsibilities

  • undefined and circular component dependencies

  • protected APIs without authentication

  • APIs without request or response schemas

  • databases without a valid owner, purpose, or backup strategy

  • infrastructure without deployment targets

  • absent logging, metrics, or alerting

  • missing failure handling and component scaling strategies

  • missing scaling approach and capacity triggers

  • absent security controls

  • very high availability claims without disaster recovery detail

  • explicit technology compatibility risks and duplicate recommendations

Scoring starts at 100 and deducts 15 per error, 5 per warning, and 2 per suggestion, with a minimum of zero. valid means there are no errors; warnings can still be present.

Diagram generation

Diagram generation is deterministic. It never sends the design to a provider.

| Type | Source data | Mermaid form |

| --------------------- | -------------------------------------- | ----------------- |

| architecture | Components and dependencies | flowchart LR |

| sequence | Components and dependency interactions | sequenceDiagram |

| deployment | Current component graph | flowchart LR |

| data-flow | Structured dataFlows | flowchart LR |

| entity-relationship | Database entities | erDiagram |

Mermaid IDs are reduced to alphanumeric/underscore identifiers. Labels remove control-sensitive punctuation and line breaks and are capped at 120 characters. Render generated text using Mermaid in your own documentation or UI layer.

Provider architecture

interface  AIProvider {

readonly  name: string;

generateSystemDesign(input, options?): Promise<SystemDesign>;

refineSystemDesign(input, options?): Promise<RefineSystemResult>;

compareSystemDesigns(input, options?): Promise<DesignComparison>;

estimateSystem(input, options?): Promise<SystemEstimate>;

}

Default OpenAI provider

OpenAIProvider uses the official OpenAI Node.js SDK, structured responses, local Zod validation, an application-controlled API key, and a default model of gpt-5-mini. Provider instructions require explicit assumptions and tradeoffs, consistent IDs, authenticated protected APIs, failure handling, backups, scaling, security, and observability.

import  { OpenAIProvider, Foundry }  from  "@labsfoundry/sdk";

  

const  provider = new  OpenAIProvider({

apiKey: process.env.OPENAI_API_KEY!,

model:  "gpt-5-mini",

timeoutMs:  30_000,

maxRetries:  2,

});

  

const  foundry = new  Foundry({ provider });

Custom AI provider

import  {

Foundry,

SystemDesignSchema,

type AIProvider,

type GenerateSystemInput,

type ProviderRequestOptions,

}  from  "@labsfoundry/sdk";

  

class  InternalProvider  implements  AIProvider {

readonly  name = "internal";

  

async  generateSystemDesign(input: GenerateSystemInput, options?: ProviderRequestOptions) {

const  response  =  await  fetch("https://architecture.example/designs", {

method:  "POST",

signal: options?.signal,

headers: { "content-type":  "application/json" },

body:  JSON.stringify(input),

});

  

if (!response.ok) throw  new  Error(`Provider failed: ${response.status}`);

return SystemDesignSchema.parse(await response.json());

}

  

// Implement refineSystemDesign, compareSystemDesigns, and estimateSystem

// with their exported schemas and result types.

}

  

const  foundry = new  Foundry({ provider:  new  InternalProvider() });

A complete implementation is available in examples/custom-provider/index.ts.

Technology data provider

The technology provider is optional and independent from the AI provider. It is available at foundry.providers.technology; applications decide when and how enrichment is merged into recommendations.

import  { Foundry, HttpTechnologyDataProvider }  from  "@labsfoundry/sdk";

  

const  technologyDataProvider = new  HttpTechnologyDataProvider({

baseUrl: process.env.FOUNDRY_TECH_API_URL!,

apiKey: process.env.FOUNDRY_TECH_API_KEY,

timeoutMs:  10_000,

paths: {

search:  "/technologies/search",

technology:  "/technologies",

},

});

  

const  foundry = new  Foundry({

apiKey: process.env.OPENAI_API_KEY!,

technologyDataProvider,

});

  

const  matches = await  foundry.providers.technology?.searchTechnologies({

query:  "PostgreSQL",

runtime:  "node20",

limit:  5,

});

Default HTTP contract:

| Operation | Request | Response |

| --------- | -------------------------------------------------------- | ------------------------------- |

| Search | POST /technologies/search with TechnologySearchQuery | TechnologySearchResult[] |

| Detail | GET /technologies/:identifier | TechnologyDetails or HTTP 404 |

The adapter accepts custom paths and a custom fetch implementation. Responses larger than 1 MB are rejected. No technology API is required for core SDK operation.

Reliability and errors

Timeout, retry, and abort flow

stateDiagram-v2

[*] --> Attempt

Attempt --> Success: valid response

Attempt --> Aborted: AbortSignal

Attempt --> Failed: permanent failure

Attempt --> Backoff: transient failure and retries remain

Backoff --> Attempt: exponential delay plus jitter

Attempt --> TimedOut: timeout reached

Success --> [*]

Aborted --> [*]

Failed --> [*]

TimedOut --> [*]

Loading

Retryable conditions:

  • network failures

  • HTTP 408, 429, 500, 502, 503, and 504

  • provider timeouts when retries remain

Non-retryable conditions:

  • invalid API credentials

  • malformed user input

  • Zod validation failures

  • malformed provider output

  • explicit request cancellation

Request options override the client timeout:

const  controller = new  AbortController();

  

const  pending = foundry.systems.generate(input, {

signal: controller.signal,

timeoutMs:  60_000,

});

  

controller.abort();

await  pending;

Typed error hierarchy


FoundryError

├── ConfigurationError

├── ValidationError

├── ProviderError

│ ├── ProviderAuthenticationError

│ ├── ProviderRateLimitError

│ ├── ProviderTimeoutError

│ └── ProviderResponseError

├── ExternalApiError

└── AbortError

Every SDK error exposes code, message, retryable, and optional statusCode, cause, and safe details.

import  { FoundryError, ProviderRateLimitError }  from  "@labsfoundry/sdk";

  

try  {

await foundry.systems.generate(input);

}  catch (error) {

if (error instanceof  ProviderRateLimitError  && error.retryable) {

// Queue for a later application-level attempt.

} else  if (error instanceof  FoundryError) {

console.error(error.code, error.statusCode);

}

}

The default logger is silent. Custom loggers must never emit credentials, authorization headers, full prompts, private application context, or raw provider responses.

Security and runtime boundaries

| Control | Implementation |

| ------------------------- | ------------------------------------------------------------------------- |

| Secret isolation | Provider construction is documented as server-only |

| Input validation | Strict Zod objects with length and numeric bounds |

| Output validation | Structured provider output plus local Zod parsing |

| Prompt injection boundary | Provider instructions treat descriptions as untrusted data |

| Credential redaction | Key/token/authorization-like fields and common token strings are redacted |

| Request cancellation | Standard AbortSignal support |

| Resource limits | Prompt serialization and external response caps |

| Mermaid safety | Sanitized node IDs and labels |

| Code execution | No eval, shell execution, or dynamic code loading |

| Deserialization | JSON parsing followed by schema validation at SDK boundaries |

Module boundaries

  • Server-only: Foundry, OpenAIProvider, and any code holding provider credentials.

  • Browser-safe logic: exported Zod schemas, validateSystemDesign, generateDiagram, and public utility types.

  • Runtime-dependent: HttpTechnologyDataProvider requires native fetch or an injected implementation.

Do not instantiate Foundry with a secret inside React client components, browser bundles, service-worker source, or publicly executable edge code where environment secrets are exposed.

Examples

| Example | Location | Demonstrates |

| ------------------- | ------------------------------ | --------------------------------------- |

| Basic Node | examples/basic-node | Generation and Mermaid output |

| Advanced operations | examples/advanced-operations | Refine, compare, estimate, cancellation |

| Express | examples/express-api | Server endpoint integration |

| Next.js | examples/nextjs-route | App Router server route |

| Custom AI provider | examples/custom-provider | Complete provider adapter |

| Technology provider | examples/technology-provider | In-memory catalog adapter |

From a repository checkout:

npm  install

npm  install  --save-dev  tsx  express  @types/express

  

npx  tsx  examples/basic-node/index.ts

npx  tsx  examples/advanced-operations/index.ts

npx  tsx  examples/express-api/server.ts

For Next.js, copy examples/nextjs-route/route.ts into app/api/design/route.ts in an existing server-rendered Next.js application.

Development and publishing

Repository structure


sdk/

├── src/

│ ├── foundry.ts # Public client and APIs

│ ├── openai-provider.ts # Default provider

│ ├── technology-provider.ts # Generic HTTP catalog adapter

│ ├── schemas.ts # Zod source of truth

│ ├── types.ts # Inferred and interface types

│ ├── validation.ts # Deterministic design checks

│ ├── diagrams.ts # Mermaid and JSON graphs

│ ├── errors.ts # Typed errors and mapping

│ ├── utils.ts # Retry, timeout, redaction

│ └── index.ts # Public exports

├── tests/ # Offline unit/integration tests

├── examples/ # Server and provider examples

├── scripts/verify-package.mjs # Built entry-point check

└── dist/ # ESM, CommonJS, declarations, maps

Quality gate

npm  install

npm  run  typecheck

npm  run  lint

npm  test

npm  run  build

npm  run  verify:package

npm  pack  --dry-run

npm run check runs type checking, linting, tests, and the build in sequence. Tests do not require external credentials. A real OpenAI integration test should only be enabled in a controlled environment with an explicit test key.

Publishing version 1.0.0

npm  login

npm  run  check

npm  run  verify:package

npm  pack  --dry-run

npm  publish  --access  public

Verify that the npm account has permission to publish the @labsfoundry scope and that the version does not already exist before publishing.

Contributing

See CONTRIBUTING.md. Keep schemas as the source of truth, avoid duplicated public types, add deterministic tests for behavior changes, and run the full quality gate before submitting changes.

License

MIT. See LICENSE.

Disclaimer

Foundry provides engineering recommendations. It does not guarantee security, regulatory compliance, infrastructure cost, availability, performance, or production fitness. Qualified humans must review architecture, security, compliance, capacity, and commercial decisions before production use.

About

Production-ready TypeScript SDK for generating, validating, refining, comparing, estimating, and visualizing AI-powered software architecture designs.

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages