eyeling

A minimal Notation3 (N3) reasoner in JavaScript.

eyeling is:

Playground (in your browser)

Try it here:

The playground runs eyeling client-side. You can:

Example (Socrates)

This link preloads a small “Socrates is Mortal” ruleset:

Quick start (Node.js)

Requirements

Install (npm)

npm i eyeling

CLI (npm)

Run on a file:

npx eyeling examples/socrates.n3

(Or install globally: npm i -g eyeling and run eyeling ....)

JavaScript API (Node)

const { reason } = require("eyeling");

const input = `
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>.
@prefix : <http://example.org/socrates#>.

:Socrates a :Human.
:Human rdfs:subClassOf :Mortal.

{ ?S a ?A. ?A rdfs:subClassOf ?B } => { ?S a ?B }.
`;

const output = reason({ proofComments: false }, input);
console.log(output);

ESM:

import eyeling from "eyeling";
const output = eyeling.reason({ proofComments: false }, input);
console.log(output);

Note: the API currently shells out to the bundled eyeling.js CLI under the hood (simple + robust).

Testing

From a repo checkout:

npm test

Or run individual suites:

npm run test:api
npm run test:examples
npm run test:package
npm run test:packlist

Run a single file

From the repo root:

# Option 1: use the shebang (Unix-like)
./eyeling.js examples/socrates.n3

# Option 2: explicit node
node eyeling.js examples/socrates.n3

By default, eyeling:

  1. parses the input (facts + rules)
  2. runs forward chaining to a fixpoint
  3. prints only newly derived forward facts (not the original input facts)
  4. prints a compact per-triple explanation as # comments (can be disabled)

Options

node eyeling.js --version
node eyeling.js -v

# Disable proof comments (print only derived triples)
node eyeling.js --no-proof-comments examples/socrates.n3
node eyeling.js -n examples/socrates.n3

What output do I get?

For each newly derived triple, eyeling prints:

  1. a proof-style comment block explaining why the triple holds (unless -n), and then
  2. the triple itself in N3/Turtle syntax.

The proof comments are compact “local justifications” per derived triple (not a single exported global proof tree).

Reasoning model

Forward + backward chaining

Forward rule premises are proved using:

The CLI prints only newly derived forward facts.

Performance notes (current engine)

eyeling stays tiny, but includes a few key performance mechanisms:

Parsing: practical N3 subset

Supported:

Non-goals / current limits:

Blank nodes and quantification (pragmatic N3/EYE-style)

eyeling follows the usual N3 intuition:

  1. blank nodes in facts are normal RDF blanks (_:b1, _:b2, … within a run)
  2. blank nodes in rule premises behave like rule-scoped universals (similar to variables)
  3. blank nodes only in rule conclusions behave like existentials: each rule firing generates fresh Skolem blanks (_:sk_0, _:sk_1, …)

Equal facts up to renaming of Skolem IDs are treated as duplicates and are not re-added.

Rule-producing rules (meta-rules)

eyeling understands the log:implies / log:impliedBy idiom.

Top level:

During reasoning:

Inference fuse — { ... } => false.

Rules whose conclusion is false are treated as hard failures:

:stone :color :black .
:stone :color :white .

{ ?X :color :black . ?X :color :white . } => false.

As soon as the premise is provable, eyeling exits with status code 2.

Built-ins (overview)

eyeling implements a pragmatic subset of common N3 builtin families and evaluates them during backward goal proving:

License

MIT (see LICENSE).