{"slug": "show-hn-open-source-alternative-to-typesafe-ai", "title": "Show HN: Open-Source Alternative to TypeSafe.ai", "summary": "A developer released an open-source template for building deterministic models with structured reasoning, positioning it as an alternative to TypeSafe.ai. The template runs JavaScript rule functions through a forward-chaining symbolic inference engine locally on Node.js with no LLM at inference time, and pairs with an agent that orchestrates a feedback loop between LLM fact extraction and deterministic rule evaluation, returning FACT_NEEDED with a fact's schema rather than guessing when facts are ambiguous. The repo includes a model knowledge base template and a symbolic-kb skill in .claude/skills/symbolic-kb/ designed to run as an Agent Skills standard skill across opencode, Claude Code, and Codex.", "body_md": "A self-contained template for building a **deterministic model** with structured reasoning. Rules are JavaScript functions executed by a forward-chaining symboling inference engine locally with Node.js — no LLM is used at inference time.\n\nTo interact with unstructured inputs, an agent can be used to orchestrate a feedback loop between LLM fact extraction and deterministic rule evaluation, refusing to guess when facts are ambiguous.\n\nThis repo contains a model knowledge base template (clone it, use the skill to modify `.kb/`, ship) and the `symbolic-kb` skill in `.claude/skills/symbolic-kb/`, which includes instructions for maintaining the knowledge base and the symbolic reasoning engine. This skill is designed to run as an [Agent Skills](https://agentskills.io) standard skill (opencode, Claude Code, Codex).\n\nA common practical example is where the deterministic code is responsible for making a decision, whereas LLM handles extraction of simple facts from the source unstructured data (a source document, a set of facts/state that need to be extracted from the text etc). The decision-making then runs until an answer can be determined:\n\n1. The agent picks the rule that answers your question, and extracts the facts it can see in the document/state.\n2. It runs the engine. If a fact is missing, the engine returns `FACT_NEEDED` with that fact's schema — never a guess.\n3. The agent goes back to the document for that specific fact (using the schema's type and description), adds it, and re-runs.\n4. Repeat until `COMPLETED` , then the agent answers with the reasoning tree attached.\n\nIn an opencode, Claude Code, or Codex session in this repo, ask:\n\nHere's a contract: \"Acme LLC and Beta Inc. agree to a 12-month non-compete. Signed by A. Smith for Acme and J. Doe for Beta.\" Is it valid according to the 'symbolic-kb' skill?\n\nThe agent extracts `contract.hasNonCompete`, `contract.signedByPartyA`, `contract.signedByPartyB` from the text, runs the inference, and answers with the reasoning tree — the same one the command-line example below prints. If a fact isn't in the document (e.g., one signature is missing), the engine stops at `FACT_NEEDED` for that fact and the agent says so rather than guessing:\n\n● Skill(symbolic-kb) Successfully loaded skill\n\nSearched for 1 pattern, ran 3 shell commands\n\nYes — valid, according to the contract.isValid rule.\n\nReasoning trace:\n\n- contract.hasNonCompete = true (12-month non-compete clause is present)\n- contract.signedByPartyA = true (A. Smith signed for Acme)\n- contract.signedByPartyB = true (J. Doe signed for Beta)\n- → contract.isSignedByBothParties = true (both signatures present)\n- → contract.isValid = true (has non-compete AND signed by both parties)\n\nFor a document on disk, point the agent at the file (attach it or give its path) and ask the same question.\n\nFor structured inputs, the same engine can be called programmatically without an LLM or an agent:\n\n```\n# 1. Query with a missing fact — the engine recurses into contract.isSignedByBothParties,\n#    finds contract.signedByPartyB missing, and stops (rules load at runtime, no build step)\necho '{\"fact\":\"contract.isValid\",\"facts\":{\"contract.hasNonCompete\":true,\"contract.signedByPartyA\":true}}' \\\n  | node .claude/skills/symbolic-kb/scripts/run_inference.mjs --kb-dir .kb \\\n  | node .claude/skills/symbolic-kb/scripts/print_tree.mjs\n# ▶ Inferring contract.isValid — Is the contract valid?\n#   contract.hasNonCompete = true (known)\n#   ▶ Inferring contract.isSignedByBothParties — Is the contract signed by both parties?\n#     contract.signedByPartyA = true (known)\n#     ✗ contract.signedByPartyB is missing (boolean) — Whether party B signed the contract\n#   ✗ inference stopped due to contract.signedByPartyB missing\n# ✗ inference stopped due to contract.signedByPartyB missing\n\n# 2. Provide all facts — inference recurses and completes\necho '{\"fact\":\"contract.isValid\",\"facts\":{\"contract.hasNonCompete\":true,\"contract.signedByPartyA\":true,\"contract.signedByPartyB\":true}}' \\\n  | node .claude/skills/symbolic-kb/scripts/run_inference.mjs --kb-dir .kb \\\n  | node .claude/skills/symbolic-kb/scripts/print_tree.mjs\n# ▶ Inferring contract.isValid — Is the contract valid?\n#   Rule: A contract is valid if it has a non-compete clause and is signed by both parties\n#   contract.hasNonCompete = true (known)\n#   ▶ Inferring contract.isSignedByBothParties — Is the contract signed by both parties?\n#     Rule: A contract is signed by both parties if party A and party B both signed\n#     contract.signedByPartyA = true (known)\n#     contract.signedByPartyB = true (known)\n#   ✓ inferred contract.isSignedByBothParties = true\n# ✓ inferred contract.isValid = true\n```\n\nA `FACT_NEEDED` response is the engine refusing to guess — supply the missing fact and re-run, or have an agent extract it from your document (see the Quick start above).\n\nTo add or change rules, describe them in natural language; the agent translates your description to first-order logic, writes the rule file, updates `manifest.json` (question, condition, dependencies), and lints the schemas.\n\nUsage example in this repo:\n\nShow me the knowledge base in this project\n\n(Prints explanation of the existing rules in the knowledge base)\n\nAdd a rule: a contract is binding if it is valid and has been filed with the county.\n\nThe agent updates the knowledge base with the additional rule.\n\nRe-run the query example to see how the updated tree executes.\n\nModern agents can use the skill to automatically *build entire reasoning knowledge base from a set of a few examples*, reverse-engineering them into a decision-making model.\n\nFor example:\n\nRedo this knowledge base to implement logic behind writing the emails. Use relevant skill to remove all existing rules, analyse the following examples and write rules that would produce all information needed to write a welcome email from the inputs: [a set of emails and when each email was sent]\n\nThe agent would then analyze a few email examples provided and reverse-engineer how each was written and how decisions about varying the examples were made based on the input variables, producing a deterministic model capable of making decisions and writing an email brief from those input variables.\n\n```\n.kb/\n  manifest.json          # Rule metadata: question, condition, dependencies schema\n  rules/\n    <rule-name>.mjs      # One async function per file (ESM, default export). Filename IS the rule name.\n  query-log.jsonl        # Append-only log of queries (written by the agent)\n```\n\nOverride the KB directory with `--kb-dir <path>` on any script, or set it in `AGENTS.md`.\n\nCopy `templates/rule_template.mjs` into `.kb/rules/<subject.predicate>.mjs`. The default-exported function takes an `infer` callback and returns a value. Use only `infer` and standard JS — no external packages.\n\n``` js\nexport default async function(infer) {\n  const hasNonCompete = await infer('contract.hasNonCompete');\n  const isSignedByBoth = await infer('contract.isSignedByBothParties');\n  return hasNonCompete && isSignedByBoth;\n}\n```\n\nThen register the rule in `manifest.json`:\n\n```\n{\n  \"name\": \"Contract Validity Checker\",\n  \"rules\": {\n    \"contract.isValid\": {\n      \"question\": \"Is the contract valid?\",\n      \"condition\": \"A contract is valid if it has a non-compete clause and is signed by both parties\",\n      \"dependencies\": {\n        \"type\": \"object\",\n        \"properties\": {\n          \"contract.hasNonCompete\": { \"type\": \"boolean\", \"description\": \"Whether the contract includes a non-compete clause\" },\n          \"contract.isSignedByBothParties\": { \"type\": \"boolean\", \"description\": \"Whether the contract is signed by both parties\" }\n        }\n      }\n    }\n  }\n}\n```\n\n`question` is what the rule answers; `condition` is the plain-English logic; `dependencies` is a JSON schema of facts the rule needs (used by the engine to ask for missing facts).\n\n```\n# Reconcile enum conflicts across rules that reference the same string fact\nnode .claude/skills/symbolic-kb/scripts/lint_schemas.mjs --kb-dir .kb\n```\n\nRules are auto-discovered at runtime — no build step. Run `lint_schemas.mjs` after manifest enum changes.\n\nThere is no compiled bundle and no build step. The KB is loaded at runtime: `load_kb.mjs` reads `manifest.json`, dynamically imports `rules/*.mjs`, and wires a `handler` via `createHandler` from `inference.mjs`. To deploy, ship `.kb/` (`rules/*.mjs` + `manifest.json`) alongside `inference.mjs` and `load_kb.mjs`:\n\n- run locally via `run_inference.mjs` (above),\n- deploy to AWS Lambda — zip `.kb/` +`inference.mjs` +`load_kb.mjs` and use`loadKB(kbDir).handler` as the entry point; Lambda reads the files at cold start, no bundler needed,\n- wrap in Express/HTTP for programmatic access, or\n- import directly in Node.js: `import { loadKB } from './load_kb.mjs'; const { handler } = await loadKB(kbDir)` .\n\nThe full agent workflows — natural-language-to-logic rule authoring, the fact-extraction feedback loop, and single-rule evaluation — live in `.claude/skills/symbolic-kb/SKILL.md`. Read that when you're ready to drive the KB from a conversation rather than the CLI.", "url": "https://wpnews.pro/news/show-hn-open-source-alternative-to-typesafe-ai", "canonical_source": "https://github.com/TitovDigital/kbai-skill", "published_at": "2026-09-18 06:04:05+00:00", "updated_at": "2026-09-18 06:25:09.270371+00:00", "lang": "en", "topics": ["ai-agents", "developer-tools", "ai-tools"], "entities": ["TypeSafe.ai", "Node.js", "Agent Skills", "opencode", "Claude Code", "Codex", "symbolic-kb"], "alternates": {"html": "https://wpnews.pro/news/show-hn-open-source-alternative-to-typesafe-ai", "markdown": "https://wpnews.pro/news/show-hn-open-source-alternative-to-typesafe-ai.md", "text": "https://wpnews.pro/news/show-hn-open-source-alternative-to-typesafe-ai.txt", "jsonld": "https://wpnews.pro/news/show-hn-open-source-alternative-to-typesafe-ai.jsonld"}}