惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

G
GRAHAM CLULEY
T
Tenable Blog
Know Your Adversary
Know Your Adversary
C
CXSECURITY Database RSS Feed - CXSecurity.com
P
Privacy International News Feed
S
Security Affairs
NISL@THU
NISL@THU
O
OpenAI News
Attack and Defense Labs
Attack and Defense Labs
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Hacker News: Ask HN
Hacker News: Ask HN
Webroot Blog
Webroot Blog
Schneier on Security
Schneier on Security
S
SegmentFault 最新的问题
S
Schneier on Security
G
Google Developers Blog
V
V2EX
C
Check Point Blog
U
Unit 42
Google DeepMind News
Google DeepMind News
T
Threatpost
阮一峰的网络日志
阮一峰的网络日志
T
The Exploit Database - CXSecurity.com
Recent Announcements
Recent Announcements
M
MIT News - Artificial intelligence
S
Secure Thoughts
博客园 - 司徒正美
Recorded Future
Recorded Future
P
Proofpoint News Feed
Spread Privacy
Spread Privacy
K
Kaspersky official blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
AI
AI
博客园 - 聂微东
N
News and Events Feed by Topic
SecWiki News
SecWiki News
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
V
Vulnerabilities – Threatpost
P
Palo Alto Networks Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Engineering at Meta
Engineering at Meta
Recent Commits to openclaw:main
Recent Commits to openclaw:main
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
酷 壳 – CoolShell
酷 壳 – CoolShell
WordPress大学
WordPress大学
The Hacker News
The Hacker News
The Last Watchdog
The Last Watchdog
Project Zero
Project Zero
W
WeLiveSecurity
博客园 - Franky

Hacker News: Show HN

PurrrrrFocus: Pomodoro Timer App - App Store Workflow Engine — Multi-Step Orchestration for Bun RapidPhoto: Pro Photo Editor App - App Store GitHub - DheerG/swarms: Achieve extraordinary results with claude code across a variety of tasks SPICE simulation → oscilloscope → verification with Claude Code — Lucas Gerads Show HN: VCoding – A 5 MB native Windows IDE with no dynamic dependencies Show HN: LLMs don't hallucinate because they're bad at math, it's the format GitHub - Agent-FM/agentfm-core: AgentFM is a peer-to-peer network that turns everyday computers into a decentralized AI supercomputer. AgentFM lets you run massive AI workloads directly across a global mesh of idle CPUs and GPUs. Show HN: Tracking Top US Science Olympiad Alumni over Last 25 Years GitHub - Potarix/agent-hub: One place to talk to all your agents Show HN: Runtime security for AI agents(injection,tool abuse, data exfiltration) GitHub - dubeyKartikay/lazyspotify: Terminal Spotify client for macOS and Linux GitHub - the-banana-tool/king-louie: Easy to use GUI Personal AI Assistant. Win/Linux/Mac. Show HN I made my vacation rental bookable by AI agents–no Airbnb, 0% commission GitHub - basteez/jsf-autoreload: maven plugin to enable hot reload on jsf projects uvm32/hosts/host-gdbstub at main · ringtailsoftware/uvm32 GitHub - labsai/EDDI: Config-driven engine that turns JSON into production-grade AI agents. Multi-agent orchestration, 12+ LLM providers, MCP/A2A protocols, RAG, persistent memory, and enterprise compliance (EU AI Act, GDPR, HIPAA). Built on Quarkus. GitHub - glitchnsec/fortyone-oss: AI Executive Assistant Platform Quickstart | Alien GitHub - muxshed/shed: One stream in, or many. Every destination, simultaneously. No cloud middleman, no per-channel fees, no limits. GitHub - ocrbase-hq/ocrbase: 📄 PDF/IMG ->.MD/JSON Document OCR API for PaddleOCR and GLMOCR. Self-hostable. GitHub - impactjo/home-memory: MCP server that lets your AI assistant remember everything about your home. GitHub - Sets88/dbcls: DbCls is a powerful terminal database client that supports various databases GitHub - neptun2000/heor-agent-mcp GitHub - SeanFDZ/macmind: Single-layer transformer in HyperTalk for the classic Macintosh RollQuation: Math Puzzles - Apps on Google Play GitHub - dropbox/witchcraft Show HN: Agent-cache – Multi-tier LLM/tool/session caching for Valkey and Redis GitHub - opentalon/opentalon: OpenTalon is an open-source platform built from the ground up in Go as a robust alternative to OpenClaw LinkedIn™ 职位抓取工具 - Chrome 应用商店 GitHub - EdoardoBambini/Agent-Armor-Iaga: AI agents are getting tool access — shell, file system, databases, APIs, secrets. But **nobody is governing what they actually do with it**. Frameworks like LangChain, CrewAI, AutoGen, and Claude Code give agents the power to execute. Agent Armor gives you the power to control, audit, and approve every single action before it happens. HN Vibes — Week 15, Apr 7–13 2026 GitHub - chojs23/ec: Easy terminal-native 3-way git mergetool vim-like workflow GitHub - SethPyle376/hiraeth: Local AWS emulator focused on fast integration testing, with SQS support, SQLite-backed state, and a debug-friendly web UI. GitHub - JakOb-dotcom/cloud-sandbox-security-analysis: Technical analysis and Proof of Concept (PoC) regarding environment variable exfiltration in containerized cloud sandboxes via side-channel data leaks. Springboards - Flint Alpha Show HN: A simpler coding agent harness GitHub - audiodude/sudomake-friends GitHub - 256thFission/mini-mythos: OSS clone of Anthropic’s Mythos harness to locate C/C++ memory vulnerabilities Show HN: OpenParallax: OS-level privilege separation for AI agent execution Hacker News Sorted - Chrome 应用商店 Show HN: How to Install Docker on Ubuntu 24.04 LTS: Complete 2026 Guide GitHub - himanshudongre/smriti GitHub - sverrirsig/claude-control: macOS desktop dashboard for monitoring and managing multiple Claude Code sessions GitHub - ory/dockertest: Write better integration tests! Dockertest helps you boot up ephermal docker images for your Go tests with minimal work. Chiral - Chrome 应用商店 Show HN: Two Claudes collaborating through shared memory on a $100 mini-PC GitHub - pmichaillat/latex-cv: Minimalist LaTeX template for academic CVs GitHub - oguzbilgic/posse: A web UI for Anthropic Managed Agents. GitHub - sshiraz/depsly: Dependency risk analysis tool for npm packages ABI Add safari/agent-harness — Safari browser automation via safari-mcp by achiya-automation · Pull Request #212 · HKUDS/CLI-Anything GitHub - Halfblood-Prince/trustcheck: Verify PyPI package attestations and improve Python supply-chain security GitHub - oguzbilgic/kern-ai: Agents that do the work and show it. GitHub - bruits/satteri: High-performance Markdown and MDX processing for the JavaScript ecosystem GitHub - tylergibbs1/feedstock: High-performance web crawler and scraper for TypeScript, powered by Bun and Playwright GitHub - Grimm67123/grimmbot: The self-improving sandboxed and open-source AI agent. With persistent memory and scheduling. GitHub - whitevanillaskies/whitebloom: Local whiteboard that blooms. GitHub - hwdsl2/docker-whisper: Docker image for a self-hosted Whisper speech-to-text server with speaker diarization and OpenAI-compatible transcription and translation APIs. Powered by faster-whisper. Supports all Whisper models, NVIDIA GPU (CUDA) acceleration, JSON/SRT/VTT output, SSE streaming, offline mode, and multi-arch (amd64, arm64). GitHub - yisding/reviewwiggum GitHub - MarwanAlsoltany/serrors: Structured errors for Go: sentinel hierarchies, typed data, custom formatting, and slog integration. GitHub - soatok/age-php GitHub - Luthiraa/markitme GitHub - stagas/rtdiff: realtime git diff gui and AI-assisted commits GitHub - tombedor/excalicharts GitHub - wh1le/excalidraw-edit: Open and edit .excalidraw files from the terminal. Offline, auto-saves to disk. MalExt Sentry - Malicious Extension Scanner - Chrome 应用商店 GitHub - syi0808/asciianimesvg: Generate animated ASCII art SVGs from text. CLI, Rust library, WASM, and web editor. GitHub - zaina-ml/ml_forge: A visual-based graph node editor for training computer vision models. GitHub - anakin87/llm-rl-environments-lil-course: 🌱 A little course on Reinforcement Learning Environments for evaluating and training Language Models GitHub - takaakit/superpowers-uml: Superpowers-UML modifies Superpowers to ensure a software development workflow in which AI agents design through UML modeling. AdriByte Studio - Sviluppo Web e Soluzioni Digitali GitHub - chouligi/angel-copilot: Your personalized Angel Investment Advisor Show HN: MoodSense AI (ML and FastAPI and Gradio, Deployed on Hugging Face) Moodsense Ai - a Hugging Face Space by aman179102 GitHub - agenteractai/lodmem: Level Of Detail Context Management for Agents GitHub - ostefani/subnetlens: A fast, concurrent network scanner with a TUI and plain-text CLI, built in Go. It discovers live hosts on your network, scans their open ports, resolves hostnames, and fingerprints operating systems—delivered. Cyber Pulse: Agentic Intel - Apps on Google Play Whisper API: Self-Hostable Speech to Text Transcription The Agent-Web Protocol Stack: A Research Thesis GitHub - msmarkgu/RelayFreeLLM: A restful API designed to route user prompts to various AI model providers. Show HN: Provepy – A Python decorator that proves your code using Lean and LLMs Show HN: Pardonned.com – A searchable database of US Pardons GitHub - patrickdappollonio/dux: Dux is a terminal UI that lets you run multiple AI coding agents side by side, each in its own git worktree, with full companion terminals, macros, commit generation, and a command palette that knows more tricks than you do. kMC Crystal Simulator Show HN: HyperFlow – A self-improving agent framework built on LangGraph GitHub - stef41/vibescore: 🎵 Grade your vibe-coded project. One command, instant letter grade across security, quality, dependencies, and testing. GitHub - stef41/lmscan: 🔍 Detect AI-generated text and fingerprint which LLM wrote it. Open-source GPTZero alternative. Zero dependencies, works offline. imgur.com GitHub - visionscaper/collabmem: Enabling long-term collaboration with Agentic AI - building up episodic and world model memory over time with in-context awareness 在 Steam 上购买 FriedrichAI: Offline AI 立省 10% GitHub - atripati/ark: AI Runtime Kernel — a context operating system for AI agents. Eliminates tool bloat, loads only what’s needed, and gives LLMs their reasoning space back. GitHub - nowork-studio/toprank: Open-source Claude Code skills for SEO, SEM, Google Ads GitHub - tacomanator/sash: Lightweight macOS menu bar app for reliably cycling through windows of the current application. Appents | Social Media Management for Product-First Teams GitHub - pnhoang/youtube-spam-blocker: Automatically detects and hides spam messages in YouTube Live chat. Set rate limits, keyword filters, and block repeat offenders. GitHub - decisionnode/DecisionNode: CLI + Local MCP - A shared structured memory store across Claude Code, Cursor, Windsurf, Antigravity, and every MCP client. Semantically queryable. GitHub - AvaCodeSolutions/django-email-learning: An open source Django app for creating email-based learning platforms with IMAP integration and React frontend components. The $100K Gap in Kubernetes Security Tooling Function Calling Harness: From 6.75% to 100%
GitHub - gabert/ontocortex: Intent-execution separation for LLM agents: the model emits typed intent (SIF) in a domain vocabulary; a deterministic layer validates, scopes, translates, and executes it. Java/Spring + Vue, with two demo domains (legal, vet).
gabert · 2026-06-25 · via Hacker News: Show HN

License: Apache 2.0 Java 21 PRs welcome

What this is. A reference implementation of a pattern: intent-execution separation for LLM agents — the model emits typed intent in domain vocabulary and never touches the substrate, while a deterministic layer validates, translates, scopes, and executes it. The project ships two deliverables, in deliberate priority order:

  1. Primary — SIF and the intent-execution separation pattern it makes concrete. The typed intent contract, and the deterministic layer beneath it that validates, translates, scopes, and executes. The load-bearing contribution; the rest of the repo exists to give it a worked, running instance. See SIF is the core.
  2. Secondary — the experimental "application as declarative content" approach. A working, agent-driven business application assembled per domain from three declarative artifacts — an ontology (a typed domain model in plain YAML), a set of business rules (plain text the agent reads), and an agent prompt (persona + interaction protocol) — over a small domain.json descriptor, with no hand-written service layer. Whether a genuinely useful application can emerge from "ontology + rules + prompt" instead of imperative code is the open question; the legal and vet domains are the evidence offered. This builds on SIF and is deliberately lower-priority. Detail: Where does the business logic live?.

Full statement of the pattern: docs/design-intent-principle.md.

Experimental, non-academic research project. Explores the boundaries of what LLMs can do as a business logic layer in ontology-driven architectures. Every hypothesis here is tested empirically against the example application shipped in this repo — the legal demo domain serves as the experimental harness, not as a showcase demo. Conclusions reached only by argument, without a running example to back them up, don't count.

How to read this. If you want to see the design running — file layout, demo domains, REST surface, what the agent does in practice — keep reading this README and explore the domains/ folder. If you want the design rationale — the tool-surface problem, the vocabulary discipline, why state machines live where they do — read docs/design-sif.md. Both views describe the same system from opposite ends.

Contents

  • SIF is the core
    • A concrete picture of routing — one ontology, two adapters
    • Why a small typed surface
    • What it buys
    • "Isn't this just SQL with extra steps?"
  • See it in action
    • 1. One question, two databases
    • 2. One instruction, one transaction
    • 3. The agent proposes, the engine decides
  • Beyond business applications
    • Where authorization fits
  • How it works
  • Where does the business logic live?
  • Tech stack
  • Prerequisites
  • Quickstart
    • 1. Clone
    • 2. Start the databases
    • 3. Build and run the backend
    • 4. Provision each domain's database
    • 5. Run the frontend and chat
  • Configuration
  • REST surface
  • Adding a new domain
  • Tests
  • Windows notes
  • Design docs
  • License

SIF is the core

SIF — Structured Intent Format — is a typed intent contract over ontology entities. It is the load-bearing piece of this project; everything else is built around it.

  • The LLM emits structured intents (find, create, update, delete, link, unlink, transition) using only the ontology vocabulary of the active domain — classes, properties, relations, transitions, value sets. It never sees SQL, physical table names, user IDs, or any storage primitive.
  • The framework validates every intent against the ontology, then routes it to whichever adapter can fulfil it. Adapters live behind the federation SPI (DataSource interface) and speak ontology types, not storage primitives.
  • An adapter can be SQL, document, key-value, REST, an internal method call, a vector store — anything that can fulfil ontology-level intents. The LLM never knows — and need not know — which adapter served a given entity.

Today two adapters ship: SqlDataSource on PostgreSQL (full CRUD plus transitions) and MongoDataSource on MongoDB (find and create; the remaining write verbs — update/delete/link/unlink/transition — are planned and currently return a recoverable "not supported"). The legal demo exercises the Mongo read path. The storage layer is a private implementation detail behind the SIF contract, not the framework's identity. Adding a method-call, REST, or vector-store adapter is a matter of writing a new DataSource implementation — the SIF surface, the ontology, and the LLM prompt stay unchanged.

That separation buys two things at once:

  1. Trust inversion. The LLM is the natural-language intent router; the framework is the trusted executor. The LLM is sandboxed by the JSON-Schema-bounded SIF grammar — it can express only declared verbs and ontology names, never SQL, shell, URLs, or any storage primitive — so a prompt-injected or hallucinating model has no expressible way to reach the substrate directly. Authorization is a separate concern: because everything below the SIF surface runs deterministically, there is one place after the LLM to enforce it. The demo ships a deliberately simple owner-scoping example there; a real RBAC/IdP plugs in at the same seam (see Where authorization fits below). It is not an authorization model.
  2. Backend neutrality. The LLM expresses what it wants; the framework decides how to fulfil it. No prompt change, no ontology change, no SIF change when an entity moves from a SQL table to a service method behind a REST endpoint.

A single ontology file in the project's compact YAML format is the source of truth for each domain. "Ontology" is informal shorthand throughout: the vocabulary is OWL-inspired, but what ships is a typed domain model in plain YAML, not an OWL ontology in the strict semantic-web sense — no reasoning, no SPARQL, no equivalence/restriction axioms, no subClassOf-driven inference. See docs/design-sif.md ("About the word ontology") for what is kept from that tradition and what is dropped.

Two domains ship. legal — a law-firm matter manager covering matters, conflict checks, documents, billable time, invoicing and hearings — is the rich proof-of-concept. vet — a veterinary clinic (owners, pets, appointments, visits, treatments, billing) — is a deliberately simple, SQL-only second domain: the same engine serving a different ontology, with nothing but declarative content swapped. Both run a single managing identity that sees the whole domain.

A concrete picture of routing — one ontology, two adapters

The shipping legal demo routes one ontology to two substrates. Most entities — Lawyer, Paralegal, Client, Matter, TimeEntry, Invoice, Hearing, ConflictCheck — live in PostgreSQL through SqlDataSource. The MatterNote entity — free-form working memos attached to matters — lives in MongoDB through MongoDataSource. The LLM sees one unified ontology and emits the same shape of SIF intent for both:

{
  "operations": [
    { "op": "find", "entity": "Lawyer",
      "filters": { "barNumber": "SBA-2026-1042" } },
    { "op": "find", "entity": "MatterNote",
      "filters": { "createdDate": "2026-06-12" } }
  ]
}

How the framework dispatches it:

Entity Adapter What the adapter does
Lawyer SqlDataSource Translates to SELECT … FROM lawyers WHERE bar_number = ? against Postgres. When a domain declares a scoping identity, an identity predicate is injected here too — the current single-role demos declare none (see Where authorization fits).
MatterNote MongoDataSource Translates the intent to a MongoDB query against the matter_notes collection. In the demo this collection is unscoped — notes are shared working memos. The adapter can scope a collection per session when its mapping declares an identityField (injected into every query); the legal demo's MatterNote mapping declares none, so every session sees all notes.

The LLM never knows one entity lives in a relational store and another in a document store. It emits the same shape of intent for both. The framework picks the adapter per resolved op's entity class via DataSourceRegistry.findFor(entity). If tomorrow a third entity moved to a method-call adapter or a REST endpoint, only the adapter implementation would change — the SIF intent, the ontology, and the LLM prompt would stay identical.

Configuration is per-domain. The legal demo's domain.json declares two data sources (primary: sql for the relational entities, documents: mongo for MatterNote), and per-adapter mapping files (mapping.yaml, mapping.mongo.yaml) bind each class to its substrate. Adding a third data source is a config addition plus a third mapping file — the SIF surface, the LLM prompt, and the rest of the ontology stay unchanged.

That is the federation primitive: not "the framework can talk to Postgres or Mongo," but "the framework serves a single ontology from multiple substrates at the same time, transparently to the LLM."

Where this fits in the value story. The heterogeneous case is where ontology most visibly earns its keep — a unified semantic vocabulary above disparate substrates. Ontology also pulls weight even within a single adapter (typed LLM tool surface, pre-execution validation, lifecycle protection, cross-domain prompt reuse, audit framing) — see docs/design-sif.md.

Why a small typed surface

LLM agents are reliable with a handful of tools and less so as the count grows — each new tool is another choice the model can pick wrong on, another set of arguments it can hallucinate. SIF keeps the agent's per-turn choice small even as the domain gets bigger: seven op verbs and an ontology of typed names — entities, properties, relationships, transitions — injected into the tool schema as enums. The agent picks slots inside a small, typed grid; it doesn't navigate a sprawling tool catalog. That is the principle the whole architecture rests on — the LLM is an intent router, not an executor — and it is given its full treatment in docs/design-intent-principle.md.

What it buys

Beyond the two payoffs already described — trust inversion and backend neutrality — the same seam yields, with no per-feature work:

  • Audit & replay. Every operation is a structured, human-readable intent record. The on-disk session log is the audit trail.
  • Conversational atomicity. One user intention ("set up the cosigner and link her to my new loan") = one submit_sif batch = one transaction at the adapter. No bespoke saga/compensation code per use case.
  • Refactor-safe. Physical schema changes (or moving an entity from a table to a service method) touch the adapter layer, not the LLM prompt. The same ontology can target multiple physical schemas (e.g. multi-tenant with isolated DBs) or mixed backends.
  • Debuggable. When something breaks, the trace shows the LLM's original intent unchanged — the bug is either in the intent or strictly downstream of it. No "did the LLM hallucinate?" guessing.

"Isn't this just SQL with extra steps?"

The fair version of the critique: SIF's modifier vocabulary (filters, aggregate, sort, limit, relations, resolve) looks SQL-shaped. It is — because relational stores serve those modifiers uniformly, so the SQL-flavoured shape is the pragmatic surface for SQL-backed entities.

What that observation misses:

  • SQL is one adapter, not the framework. A method-backed entity and a SQL-backed entity look identical to the LLM. The framework decides which adapter serves which class. The LLM never writes SQL, never reads SQL, never knows SQL is involved.
  • The verbs are backend-neutral. find, create, update, delete, link, unlink, transition are ontology-level intents, not relational operations. A REST adapter fulfils them with HTTP calls; a method-call adapter dispatches them to service methods.
  • The modifiers degrade gracefully. Non-SQL adapters honour the subset of modifiers their backend supports and reject the rest with a structured FederationException — the same recoverable refusal pattern the SQL translator already uses for "cannot build join path."
  • SIF is deliberately smaller than SQL. No GROUP BY, no HAVING, no UNION, no window functions, no raw expressions, no subqueries outside resolve. Not more expressive than SQL — less expressive than SQL, in exactly the dimensions where less is safer.
  • An established pattern in the same direction. GraphQL, OData $filter, DynamoDB ExpressionAttributes — all chose smaller-than-SQL typed DSLs for the same reason: the calling layer cannot be fully trusted, so the language it speaks must be one the server can mechanically validate, scope, and execute.

See it in action

The screenshots below are the legal demo running end to end — nothing is mocked. In each, the left pane is the business user's conversation; the right "under the hood" pane is the live SIF trace: the typed intent the LLM emitted, the SQL or Mongo query it was deterministically translated to, and the result handed back.

1. One question, two databases

A matter's structured record lives in PostgreSQL; its free-form working notes live in MongoDB. The user neither knows nor cares which store holds what — they ask one question, and the framework fans a single batch of intent out to both substrates.

Prompt: In a single batch, look up two things for matter MTR-2023-001: the Matter record itself, and its working notes (entity MatterNote, where aboutMatter is MTR-2023-001).

Legal demo — one SIF batch resolving a matter from Postgres

One submit_sif batch carries two find ops. The trace shows the first op translated to SELECT … FROM lgl_matters WHERE matter_number = :p1 against Postgres, and the conversation already shows the assembled answer — the matter record together with its three working notes.

Legal demo — the same batch's second op as a MongoDB find

Scrolling the same trace down to the second op: a green MONGO find against the matter_notes collection with query {"matterId": "MTR-2023-001"}, returning the notes from MongoDB. One intent, two substrates — and no SQL or Mongo syntax ever crosses the LLM boundary.

2. One instruction, one transaction

A single natural-language instruction that touches two entities. The agent resolves the matter and both staff members by name, then writes a billable time entry and a follow-up task as one atomic batch.

Prompt: On matter MTR-2023-001, log 3.5 hours of billable time for Derek Okafor reviewing the expert report, and open a task for Sofia Ramirez to assemble the exhibit bundle due 2024-04-12.

Legal demo — the agent confirms the time entry and task, with the resolution finds in the trace

The conversation confirms both records were created. The trace opens with the resolution finds — locating the matter and the two staff members by name before any write happens.

Legal demo — the create intent carrying two ops in one batch

The create intent itself: two ops — a TimeEntry and a Task — submitted together in a single submit_sif batch.

Legal demo — the two generated INSERT statements with foreign-key sub-selects

The deterministic translation: two INSERT … VALUES (…, (SELECT lgl_matter_id …), (SELECT lgl_staff_id …)) statements. Foreign keys are resolved by sub-select from the names the user gave, and both inserts commit in one transaction — one instruction, one atomic unit of work.

3. The agent proposes, the engine decides

Lifecycle changes are governed by a declared state machine, not by the model's judgement. Here the user asks for a transition that isn't legal from the matter's current state.

Prompt: Run the Engage transition on matter MTR-2023-001 now.

Legal demo — the engine rejecting an illegal transition with a structured error

The LLM emits a transition intent — and the engine refuses it: current state 'active' is not in the legal source set [conflict_check]. Engage is only legal from conflict_check, and this matter is already active. The model cannot override the guard; it receives the structured error and explains the refusal back to the user. The LLM proposes; the deterministic layer decides.


Beyond business applications

The shipping demo exercises a business-data domain (legal), but the construction is general. Anywhere an agent acts on a typed, structured surface — files, devices, messages, deployments, regulated records — the same shape applies: a typed intent surface declared up front, a deterministic translator from intent to effect, identity injection after the LLM, and, for anything with a side effect, a declared transition bound to a post-action. The LLM only ever emits SIF — never a shell command, an SMTP exchange, or a device API call. Two concrete intents, in different domains:

Send an email — an action with a side effect. The model drafts the message field by field with create, then fires it with a transition; both ops ride in one batch, so they commit together:

{
  "operations": [
    { "op": "create", "entity": "Email",
      "data": { "to": "client@acme.com",
                "subject": "Engagement letter",
                "body": "Your engagement letter is ready to sign." } },
    { "op": "transition", "entity": "Email", "transition": "send" }
  ]
}

send is a declared transition (draft → sent); its smtpSend post-action opens the connection and dispatches the message. The wire protocol, auth, and retries live in code the model never authors. And like the vehicle below, send can carry preconditions that run before the message leaves — a recipient allowlist, a content scan that blocks sensitive data in the body or attachments (DLP), or a human-approval gate. The model fills the fields; the framework decides whether the mail is allowed to go out.

Set a vehicle's speed — a safety-gated physical command. Vehicle is the entity; the target speed is one of its fields, and applying it is a gated transition. The session is scoped to its own vehicle, so the intent names no VIN — it just writes the setpoint, then asks to enact it. Writing the field is inert, and the model does not get to decide whether enacting is safe:

{
  "operations": [
    { "op": "update", "entity": "Vehicle", "data": { "targetSpeedKph": 30 } },
    { "op": "transition", "entity": "Vehicle", "transition": "applySpeed" }
  ]
}

Writing targetSpeedKph only records a wish — nothing moves. The applySpeed transition is where authority lives: it runs its declared preconditions first — surroundingsClear (sensor fusion), withinPostedSpeedLimit (map and sign data), withinDynamicLimits (traction and road conditions) — and only if all pass does the commandPowertrain post-action send the setpoint to the drive controller. If a gate fails, the transition is rejected with a structured error the agent reads and reasons about; it cannot override the gate, raise the limit, or reach the controller directly. The agent supplies intent; the framework keeps authority over whether the car moves.

None of these domains ship (the demos run SQL + Mongo), but nothing about them is special-cased: each is a new adapter plus a few declared transitions behind the unchanged SIF surface. (For brevity the enacting snippets elide the row-locating filters that update and transition carry in real SIF — here the target is the entity created in the same batch, or the session's identity-scoped row.) For more, framed as where the architecture could go rather than what ships, see docs/design-bounded-agency.md.

Where authorization fits

Authorization is not a pillar of this project, and the framework does not ship an authorization model. What it offers is a seam and a simple demonstration of it.

Because the LLM emits typed intent and never touches the substrate, there is a single deterministic point — after translation, before execution — where authorization can be enforced. That is a genuinely useful place: the model can't read or remove what's applied there, and every operation that passes through is a structured, auditable record (verb, entity, typed args, session identity, transaction) rather than a shell transcript or pixel stream.

The framework provides that seam: a flat post-translation injector scopes a session to the rows it owns (e.g. a client seeing only their own matters). That is a teaching example, deliberately minimal — not a real authorization system. Roles, fine-grained read/write, delegation, and hierarchies are the domain of dedicated engines (Keycloak, OPA, an RBAC/ABAC service), and they plug in at exactly this seam. The framework does not try to reimplement them.

Caveat — the shipped demos don't exercise scoping today. Both legal and vet now run a single managing identity (CaseManager / ClinicManager) that sees the whole domain: their identity entity is referenced by no other table, so the injector adds no predicate. The seam, the injector, and the IdentityScope mechanism are exactly as described; they're simply dormant in the current single-operator demos. A domain that declares an owner-scoped identity (e.g. a client, a pet owner) reactivates the live demonstration with no code change — only content.

What makes the seam worth having, whichever engine fills it: enforcement is below the LLM. Identity predicates and preconditions are applied by the deterministic layer after the model runs; the LLM neither sees nor can bypass them. (That the LLM also can't emit effect code in the first place is the trust-inversion point from SIF is the core.)

There is also an approval seam between resolve and execute — the framework produces a structured plan there that could be gated (an interactive prompt, RBAC plus dry-run, cryptographic signoff). Nothing pauses there today; it is an extension point, not a feature.


How it works

Schema design pipeline (one-time per domain, fully deterministic — no LLM, no API key)

<domain>.ontology.yaml
    → Planner            (deterministic)        →  <domain>_schema_plan.yaml
    → Builder            (deterministic)        →  module_<name>.json per module
    → Reconciler         (deterministic)        →  <domain>_schema.json
    → SchemaInstaller    (deterministic)        →  CREATE TABLE … in Postgres
    → loadSeedSql        (deterministic)        →  INSERT … from the checked-in
                                                  <domain>_seed_data.sql fixture

Every step is exposed under POST /api/domains/{domain}/provision/....

SIF Engine (deterministic, LLM-free at runtime)

SIF operation (ontology vocabulary)
    → SifParser     →  typed Find / Create / Update / Link / Transition / ...
    → SifResolver   →  resolved against the OntologyModel
    → SifExecutor   →  picks the DataSource per resolved op's entity class
        ↓
    DataSource adapter (per ontology class)
      ─ SqlDataSource     →  translator → IdentityInjector → JDBC → Postgres
      ─ MongoDataSource   →  translator → MongoDB collection (find + create)
      ─ (future) MethodCallDataSource  →  dispatch to a service method
      ─ (future) RestDataSource        →  HTTP request to an external API

The SIF surface and the federation SPI (DataSource interface) speak ontology types. Each adapter privately decides how to fulfil the intent. Today SqlDataSource (full CRUD plus transitions) and MongoDataSource (find + create) ship; the others are concrete extension points the architecture already supports — same interface, same SIF contract, no LLM-facing changes when an adapter is added.

LLM Agent (one consumer of the SIF Engine)

User question
    → ConversationAgent (Claude)
        ├── system prompt = ontology + business rules + persona
        ├── tool = submit_sif (entity/relation/transition names baked in)
        ├── loop: LLM → tool_use → SifExecutor → tool_result → LLM …
        └── final text reply

The agent speaks ontology vocabulary; everything below the SIF surface runs deterministically.


Where does the business logic live?

This section is the project's second deliverable (after SIF): the experiment of assembling a working application from declarative content — ontology + business rules + agent prompt — rather than from hand-written code. The rest of this section is the evidence for whether that holds up.

Switching domain does not switch applications. The sidebar's domain dropdown swaps the active ontology, its business rules, and the LLM persona — nothing else. The same engine, REST API, JVM, and codebase serve every domain. Adding a new domain is purely a content addition: four small files describe the domain, and the agent immediately speaks that vocabulary.

Side effects that aren't pure content: the per-domain DB schema must be installed (the provisioner builds and runs it deterministically from the ontology) and any transition handler classes are Java implementations shipping alongside the ontology under domains/<name>/_generated/. Those are the only places real code lives.

A working domain in this repo carries very little code. Take domains/legal/:

domains/legal/
├── domain.json              — descriptor: data sources, identity entities, file pointers
├── legal.ontology.yaml      — entities, properties, relationships, transitions
├── legal.rules              — business rules in plain text (=== SECTION === headers)
└── legal_prompt.txt         — agent persona + identity protocol

That's the whole per-domain surface. Four small files of declarative content — the demos ship ontology-only; the physical schema and mapping are generated by provisioning.

Everything else is produced by the framework:

  • the physical schema (CREATE TABLE statements, FK declarations) — generated deterministically from the ontology by the provisioner pipeline;
  • the SQL the agent runs at runtime — produced per request by the translator from the resolved op + mapping;
  • input validation that catches typos and out-of-vocabulary names before they reach the database — driven entirely by the ontology;
  • the audit trail, identity scoping, and transaction control — generic, applied uniformly to every domain;
  • demo data is a checked-in seed_data.sql fixture loaded deterministically in one transaction — beyond that baseline, records are created by talking to the agent, not by any LLM seed-generation step (the provisioner has no LLM call at all).

The exception is the demonstration transitions. Generated Java handlers under domains/<domain>/_generated/ are wired to the precondition and post-action names declared in the YAML — conflictCheckCleared, createEngagementLetter, notifyClientInvoiceIssued, and so on. In the demo these are no-op stubs: preconditions return success, post-actions trace the call and return. They exist to show where imperative business code plugs in — the registered-interceptor escape hatch described in docs/reference-sif-vocabulary.md — not as a worked implementation. Even so, the names that bind to Java live in the ontology; the Java is just the implementation slot behind a declarative entry.

What's worth noting once the pieces come together: the reason it works isn't that the LLM is unusually powerful — it's that:

  • most of a domain (structure, lifecycle, constraints) really does fit in declarative form once you have the right primitives;
  • the framework does a lot of generic lifting below the surface — type resolution, SQL translation, identity injection, transaction control;
  • the LLM never writes code or SQL. It only picks ontology terms out of the typed grid the tool-schema builder injects, so what looks like business reasoning is actually a constrained selection task.

This isn't free. The LLM has cost and non-determinism, prompts need iteration, the ontology format is opinionated, and not every domain fits cleanly. But for the kind of problem this targets — an agent operating on real business data with rules, lifecycles, and audit trails — the amount of new code needed to add a working application stays small. That is the observation worth highlighting.


Tech stack

Component Technology
Backend Java 21, Maven multi-module
Web framework Spring Boot 3.3 (only in ontocortex-app)
Ontology Compact YAML format, OWL-inspired vocabulary (Apache Jena 5 retained for the legacy TTL parser)
Federation SPI DataSource interface in ontocortex-federation — backend-neutral
Shipping adapters SqlDataSource on PostgreSQL 15 (JDBC) and MongoDataSource on MongoDB 7 (find + create) — the SIF contract is the same for both
LLM Claude (Anthropic Messages API via the JDK HttpClient)
Frontend Vue 3 + Vite + TypeScript
Containers Docker — PostgreSQL + MongoDB (and Testcontainers spins up both for integration tests)

Prerequisites

  • JDK 21 (configured as a Maven toolchain — see ~/.m2/toolchains.xml)
  • Node 20+ (for the frontend)
  • Docker (for the bundled Postgres + Mongo and the Testcontainers-backed tests)
  • An Anthropic API key — console.anthropic.com. Only required for the LLM Agent (/chat); SIF and the entire deterministic provisioner pipeline run without it.

Quickstart

The full path from a clean checkout to a working chat is the five steps below — do them in order.

Provisioning is manual and REST-driven. Creating the database tables and loading the demo data is not done by the UI and does not happen automatically when the backend starts. You trigger it yourself by POSTing to the /provision/* endpoints (step 4). The docker-compose databases start empty; until you provision, the agent answers every question with no data. There is no CLI shim and no "provision" button — any HTTP client works.

Run the commands below from the repo root. The provisioning calls use curl, which is cross-platform; any HTTP client works. On Windows substitute mvn.cmd for mvn (see Windows notes).

1. Clone

git clone https://github.com/gabert/ontocortex.git
cd ontocortex

2. Start the databases

Brings up both containers — ontocortex_postgres (the primary SQL source) and ontocortex_mongo (the documents source for MatterNote). On a fresh volume the Postgres container auto-creates the per-domain databases (legal_demo, vet_demo) from docker/postgres-init/; step 4 then creates the tables inside them and loads the data. The stores otherwise come up empty. (If you have an old volume from before this init script existed, recreate it: docker-compose down -v && docker-compose up -d.)

3. Build and run the backend

Runs on port 8080 — leave it running.

export ANTHROPIC_API_KEY=sk-...             # only needed for /chat; provisioning is keyless
mvn -f engine/pom.xml install -DskipTests    # build + install all modules
mvn -f engine/pom.xml -pl ontocortex-app spring-boot:run

On Windows use mvn.cmd (and set the key with $env:ANTHROPIC_API_KEY = "sk-...") — see Windows notes. Without an API key the app still boots and the entire /provision/* pipeline works — only /chat returns HTTP 409 with a clear error.

4. Provision each domain's database

Required, manual. This is the step that's easy to miss. The containers from step 2 are empty, so you must create the tables and load the demo data yourself. The deterministic build artifacts (schema_plan.yaml, module_*.json, schema.json, seed_data.sql) are already committed in the repo, so for the shipped legal and vet demos you only need the two calls that touch the live databases — create the tables, then load the seed data:

curl -X POST http://localhost:8080/api/domains/legal/provision/install        # CREATE TABLE …
curl -X POST http://localhost:8080/api/domains/legal/provision/install/seed   # load seed data

install returns the created table names. install/seed loads every data source the domain declares in one call — it runs seed_data.sql into Postgres and, for a domain with a document store (legal's MatterNote), loads seed.mongo.json into MongoDB. It returns { "inserts": <sql-rows>, "documents": <mongo-docs> }; for legal expect 6 documents. There is no separate Mongo seed step and nothing platform-specific — the same curl does both stores.

Repeat for vet (or any domain you add) by swapping the name in the path (vet is SQL-only, so its documents count is 0):

curl -X POST http://localhost:8080/api/domains/vet/provision/install
curl -X POST http://localhost:8080/api/domains/vet/provision/install/seed

That's everything a fresh checkout needs — the committed schema artifacts already cover the planning steps. (The full pipeline planbuildreconcileinstallinstall/seed, plus install/drop to start over, lives in the REST surface table; you only need it if you change a <domain>.ontology.yaml.)

5. Run the frontend and chat

Runs on port 5173; proxies /api/* to the backend on :8080.

cd frontend
npm install
npm run dev

Open http://localhost:5173. Pick a domain in the sidebar, optionally set X-User-Id for identity scoping, and chat. The right pane shows, per turn, the LLM's submitted intent, each SIF operation (including transitions), the generated SQL or MongoDB query, and the row count for each.


Configuration

All runtime config lives in engine/ontocortex-app/src/main/resources/application.yaml under the engine: key. Spring Boot's relaxed binding accepts environment-variable overrides (ENGINE_API_KEY, ENGINE_MODELS_CHAT, etc.).

Key Purpose
engine.api-key Anthropic API key (typically ${ANTHROPIC_API_KEY})
engine.models.{chat,analyzer} Model IDs per pipeline role (chat agent + error-analysis post-mortem)
engine.chat.{max-tokens,max-retries,retry-delay,max-iterations} Conversation runtime
engine.log-dir Per-session debug JSONL + error post-mortems
engine.domains-dir Where domain content folders live
engine.data-sources.<name>.{dbname,user,password,host,port} Per-data-source DB credentials

REST surface

Method + path Description
GET /api/domains List available domains
GET /api/domains/{domain} Domain summary
GET /api/domains/{domain}/schema Reconciled schema.json
GET /api/domains/{domain}/schema/description Human-readable schema dump
POST /api/domains/{domain}/provision/plan Run the deterministic planner
POST /api/domains/{domain}/provision/build Deterministic builder
POST /api/domains/{domain}/provision/reconcile Merge module builds into schema.json
POST /api/domains/{domain}/provision/install CREATE TABLE …
POST /api/domains/{domain}/provision/install/seed Seed every data source: seed_data.sql → Postgres, seed.mongo.json → Mongo
POST /api/domains/{domain}/provision/install/drop Drop every table
POST /api/domains/{domain}/sif Execute a SIF batch (no LLM) — X-User-Id header for identity scoping
POST /api/domains/{domain}/chat Talk to the agent (needs API key)X-User-Id for identity scoping
DELETE /api/domains/{domain}/chat Clear conversation history for this user

Adding a new domain

  1. Create domains/<name>/ with:
    • domain.json — descriptor (name, data sources, file pointers)
    • <name>.ontology.yaml — ontology in the project's compact YAML format (see docs/reference-ontology-yaml-format.md)
    • <name>.rules — business rules (plain text with === SECTION === headers)
    • <name>_prompt.txt — agent persona / system prompt fragment
  2. Add a data-sources.<name> block to application.yaml.
  3. Drive the provisioner pipeline via the REST endpoints above.

The framework discovers the new domain automatically on the next request — no code changes, no restart for content edits beyond reloading the affected application.yaml.


Tests

mvn -f engine/pom.xml test

All 431 tests pass with Docker running. 62 of them are Testcontainers-backed integration tests — SifExecutorTest, SchemaInstallerTest, StiIntegrationTest, DemoDomainProvisioningTest, MongoDataSourceIntegrationTest, and the 11-step EndToEndTest — which spin up real Postgres + MongoDB containers; the remaining 369 are pure unit tests with no external dependency. All LLM-using code (BaseAgent retry, ConversationAgent tool-use loop, AgentPipeline rollback) is unit-tested against a fake LlmClient — no live API calls in CI.


Windows notes

Use PowerShell mvn.cmd (not the bash mvn shell script). The bash environment on Windows often picks up the wrong JAVA_HOME and a different trust store, which surfaces as toolchain mismatches or PKIX TLS errors when fetching dependencies. Maven 3.9+ with the JDK 21 toolchain config (already in engine/pom.xml) works out of the box from cmd or PowerShell.

For Git over HTTPS the same PKIX wall can appear — use SSH for origin to sidestep it.


Design docs

In-depth design notes and reference specs live in docs/ — see docs/README.md for an annotated index that tags each doc as reference or design.


License

Apache License 2.0.

Copyright 2026 Robert Gallas.