tln-language

module
v0.20.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 16, 2026 License: Apache-2.0

README

tln

A domain-agnostic expert system language with built-in ML primitives.

CI License Go


tln introduces a new concept: Expert-in-the-Loop. Instead of a human reviewing every AI decision, a deterministic expert system sits alongside the LLM — reasoning over facts, enforcing policies, and predicting outcomes. The LLM handles conversation and intent. tln handles knowledge and inference. They work together.

What is tln?

tln is a rule language for building expert systems. It reasons over structured facts from any data source — inventory, CRM, ERP, IoT sensors, ticketing systems, or anything that produces structured data. Rules detect patterns, enforce policies, predict outcomes, and automate workflows.

tln is:

  • Domain-agnostic — works for fleet management, construction, supply chain, HR compliance, hospitality, sales optimization, or any domain with structured data.
  • Readable — rules look like English. A domain expert can read, write, and audit them without programming experience.
  • Adaptive — thresholds learn from each tenant's own data. Rules get smarter over time.
  • Deterministic — detections are explainable and auditable. No black-box predictions.
  • Testable — rules have their own test framework (.tln.test files).

Example

A construction site is burning through cement faster than expected. tln detects it, forecasts when stock hits zero, and tells procurement exactly how much to order:

detect "Cement running low" {
  for records where type == "stock_item"
    and attr "name" == "Portland Cement 50kg"
    and attr "current_stock" <= attr "minimum_amount"
    and status == "active"
  flag matching items
  label "{item.name}: {attr.current_stock} bags left (minimum: {attr.minimum_amount})"
  priority CRITICAL
}

forecast "Cement stock-out date" {
  for records where type == "stock_item"
    and attr "name" == "Portland Cement 50kg"
  series attr "current_stock" over last 30 days
  predict days_until value <= 0
  when days_until < 7
  label "{item.name}: stock hits zero in ~{days_until} days at current usage"
  priority CRITICAL
}

recommend "Order cement" {
  when detect "Cement running low" matches
  calculate avg_weekly from activities
    where type == "consume" within last 30 days
  suggest "Order {avg_weekly * 4 - attr.current_stock} bags of {item.name}
           to cover 4 weeks at current consumption (~{avg_weekly}/week)"
}

No LLM involved. No API calls to figure out what's running low. tln watches the data and tells you before the site stops.

Installation

Each tagged release publishes a tln binary for linux/amd64, linux/arm64, darwin/amd64, darwin/arm64, and windows/amd64. Grab one from the Releases page or use the snippet for your platform:

# macOS (Apple Silicon) — adjust the URL for linux/x86_64 etc.
TAG=$(curl -sL https://api.github.com/repos/opentalon/tln-language/releases/latest | grep '"tag_name"' | cut -d '"' -f 4)
curl -fsSL "https://github.com/opentalon/tln-language/releases/download/${TAG}/tln-${TAG}-darwin-arm64.tar.gz" \
  | tar -xz
./tln version

Every release ships with a SHA256SUMS.txt file in case you want to verify the download.

From source

If you already have Go 1.25+ installed:

go install github.com/opentalon/tln-language/cmd/tln@latest
tln version
Try the REPL

The fastest way to see tln in action — load a real example, evaluate every block, and trace one to see the per-step query plan:

tln repl
tln> :load examples/insurance_claims.tln
  loaded examples/insurance_claims.tln: 5 block(s), 0 fact(s)
tln> :load test/insurance_claims.tln.test
  loaded test/insurance_claims.tln.test: 0 block(s), 28 fact(s)
tln> :eval all
  "Auto-approve in-network routine": 1 detection(s) — records [902]
  "Out-of-network provider":         1 detection(s) — records [904]
  "Over the per-visit cap":          2 detection(s) — records [903 904]
  "Reject blacklisted provider":     1 detection(s) — records [901]
tln> :trace "Over the per-visit cap"
  "Over the per-visit cap": 2 detection(s) — records [903 904]
    trace:
    step 1  DatalevinQuery → candidates  (rows: [903 904])
    step 2  GoComputation render_template → detections

The full walkthrough — including how to read trace output, the LLM-extracts-facts-then-Tln-decides pattern from Code Mode for MCP, and what each REPL command does — is in docs/repl.md.

FactStore backends

tln run picks its built-in fact backend with --store:

Backend When to use Setup
datalevin (default) Production today. JVM sidecar, native Datalog, FTS, raft. cd datalevin-server && clojure -M:run
memory REPL, demos, unit tests, CI smoke runs. Entirely in-process. None — works out of the box

Backends are pluggable: any type implementing the public pkg/factstore.FactStore SPI can be wired in via the Go SDK's tln.WithFactStore(...) — tln core has zero Go dependency on any database.

tln-db — Go-native backend (plugin)

opentalon/tln-db is the Go-native backend: an embedded bbolt store with roaring-bitmap + HNSW vector indexes, served over gRPC (tlndb-server). It used to live in core as the --store talon-db adapter; it was cut from core and now lives in its own repo, where tlnstore implements pkg/factstore.FactStore directly — so the language stays storage-agnostic and code-free at the boundary.

# 1. run the server (embedded bbolt, gRPC over a Unix socket)
tlndb-server --db ./tln.bbolt --socket /tmp/tlndb.sock
// 2. wire it into tln.Run via the SPI — no adapter shim
import (
    "github.com/opentalon/tln-language/pkg/tln"
    "github.com/opentalon/tln-db/tlnstore"
)

cli, _ := tlnstore.NewClient(ctx, "unix:///tmp/tlndb.sock")
tln.Run(ctx, program, tln.WithFactStore(tlnstore.New(cli)))

It also serves the HNSW index behind find similar (see Vector similarity).

Plugins & bundling (mod.tln)

tln core is plugin-free — every external capability is a plugin behind an SPI (ToolResolver for tools, FactStore for stores). You add them the way Ruby's Bundler adds gems: declare them in mod.tln, run tln bundle, and tln run uses them — no Go.

# mod.tln  — one line per plugin (source defaults to github.com/opentalon/tln-<name>)
plugin "mcp"    "v0.1.0"
plugin "io"     "v0.1.0"
plugin "prolog" "v0.1.0"
plugin "asp"    "v0.1.0"
# rules.tln  — name a plugin with `connector`, call it with `tool`
connector "inventory" via mcp    { endpoint env "INV_URL" bearer env "INV_TOKEN" }
connector "reason"    via prolog { }

workflow "demo" {
  step "list"  { tool "inventory" "list-items" { query "x" } }
  step "kin"   { tool "reason" "query" { program "parent(tom,bob). ancestor(X,Y):-parent(X,Y)." goal "ancestor(tom, D)" } }
}
tln init demo && cd demo   # scaffold mod.tln + rules.tln
tln bundle                 # like `bundle install`: compile the declared plugins in
tln run rules.tln          # connectors resolve; no main.go, ever

Go can't load Go code at runtime without a dependency cycle (core must never import a plugin), so tln bundle generates a bootstrap and compiles a project-local tln with the plugins baked in (registering each plugin's Factory via WithPlugin). Credentials come from the environment via env, never inlined — and env is valid only inside a connector, so secrets can't leak into labels, facts, or tool args. Design: ADR 0013.

The four base plugins (tln-mcp, tln-io, tln-prolog, tln-asp) each expose a Factory; any GitHub module with one is a plugin (use from "…" for a non-conventional path).

The backing store — Active Record style

The store is chosen by config, defaulting to in-memory. Add a store plugin to mod.tln and a config/store.tln, and that becomes the store — same program, no code change:

# mod.tln
plugin "db" "v0.1.0" store
# config/store.tln  (absent → in-memory)
store db { target env "TLNDB_ADDR" }

Precedence: host WithFactStore > the mod.tln store plugin + config/store.tln

in-memory. One store per project. (tln-db is a sidecar — the bundle carries the client; tlndb-server runs separately.)

Architecture

graph TB
    subgraph Sources["Data Sources (any system)"]
        MCP1[MCP Server A]
        MCP2[MCP Server B]
        MCP3[MCP Server ...]
        API[REST / Webhooks]
    end

    subgraph Compiler["tln Compiler (Go)"]
        direction TB
        LEX[Lexer]
        PAR[Parser]
        VAL[Validator]
        QP[Query Planner]
        LEX --> PAR --> VAL --> QP
    end

    subgraph Runtime["tln Runtime"]
        direction TB
        EVAL[Rule Evaluator]
        ML[ML Primitives]
        MCP_OUT[MCP Interface]

        ML --- |predict, forecast,<br>anomaly, cluster,<br>classify, similar| EVAL
        MCP_OUT --- |call tools,<br>remediate,<br>workflows| EVAL
    end

    subgraph Store["FactStore (pluggable)"]
        FACTS[(Facts)]
        STATS[Running Statistics]
        MODELS[Trained Models]
        FEEDBACK[User Feedback]
    end

    subgraph Plugins["Packages (tln.mod)"]
        STD_LOG[std/logger]
        STD_TIME[std/time]
        STD_STR[std/strings]
        CUSTOM[custom packages]
    end

    subgraph Output["Output Surfaces"]
        CHAT[Chat Alerts]
        REPORT[Scheduled Reports]
        DASH[Dashboard Widgets]
        GUARD[Policy Blocks]
    end

    TLN[".tln source files"] --> Compiler
    Compiler --> Runtime
    Runtime --> Output

    Sources --> |facts| Store
    Store <--> Runtime
    Plugins --> Runtime

    style Sources fill:#fef2f2,stroke:#ef4444
    style Compiler fill:#eff6ff,stroke:#2563eb
    style Runtime fill:#f0fdf4,stroke:#22c55e
    style Store fill:#fffbeb,stroke:#f59e0b
    style Plugins fill:#faf5ff,stroke:#a855f7
    style Output fill:#eff6ff,stroke:#2563eb
How data flows
  1. Facts come in — MCP tool results, API responses, webhooks, or any structured data source feed facts into the FactStore.
  2. Rules compile.tln files are compiled by the tln compiler (Lexer, Parser, Validator, Query Planner).
  3. Rules evaluate — the runtime queries the FactStore, runs ML primitives, and produces detections, predictions, and recommendations.
  4. Results go out — detections surface as chat alerts, scheduled reports, dashboard widgets, or policy blocks.

Block Types

Block Purpose Question it answers
detect Find patterns in data "What's wrong? What's unusual?"
rule Enforce constraints "Is this action allowed?"
recommend Suggest actions "What should I do about it?"
combine Find optimal combinations "What's the best mix?"
define Reusable conditions (helper, used by other blocks)
derive Derived facts (Datalog rules) "What follows from what I know?"
workflow Multi-step MCP orchestration "Do these steps in order."
model A trained ML model with inline fitted params "Classify/predict from a pinned model."
module Namespace + export reusable blocks "Package this and import it elsewhere."

Plus forecast, cluster, classify, predict, find similar, find related, on (reactive), constraint, enrich, collect, and cached threshold.

ML Primitives

tln has built-in ML keywords. Not heavyweight neural nets — lightweight statistical primitives that run in milliseconds on structured data.

Keyword What it does Under the hood
learned_threshold Adaptive parameter from tenant's own data Aggregation (avg, percentile)
is anomaly Flag statistical outliers Z-score, IQR, or MAD
cluster by Group similar records DBSCAN
predict Likelihood of an outcome Decision tree (interpretable)
classify Categorize records kNN over feature vectors
forecast When will a value hit a threshold? Exponential smoothing
find similar Records resembling a given one Cosine similarity, or HNSW vector index via the tln-db plugin

Every prediction is explainable. A decision tree says "this item is at risk because operating_hours > 2000 AND repair_count > 3." The user can read the reasoning.

ML modules — train once, reference many

predict and classify can train inline (trained_on records where …) or draw from a pre-fitted model — the model analog of a cached threshold. A model carries its fitted params inline (version-pinned in source with computed_from / valid_until), so there is no per-run training. Package models under a module namespace and import them by name across files:

// fleet_ml.tln
module "fleet.ml" {
  export model "failure_risk" {
    classify knn k 3
    features [attr "km", attr "age"]
    fitted {
      example [50000, 8] label "high"
      example [10000, 2] label "low"
    }
    computed_from "1204 labeled vehicles"  valid_until "2026-12-31"
  }
}

// app.tln
import "fleet.ml"                        // by module name, not file path
classify "Vehicle failure risk" {
  for records where type == "vehicle" and status == "open"
  using model "fleet.ml.failure_risk"
  confidence >= 0.9
}

kNN models store their labeled examples (lazy); decision-tree models store the fitted tree itself (fitted tree { node … }, eager). Models resolve from two providers under the same qualified name — tln model blocks and models a host registers in Go — so an embedding host can serve production models tln source references transparently.

Control flow and string functions

tln stays declarative where it counts, but action bodies (today: remediate) support imperative control flow — if/else, for each, and a bounded while — branching on the same condition grammar the rest of the language uses:

remediate {
  if attr "priority" == "CRITICAL" {
    tool "ops" "page_oncall" { vehicle attr "id" }
  } else {
    tool "ops" "open_ticket" { vehicle attr "id" }
  }
  for each channel in ["fleet-ops", "maintenance"] {
    tool "slack" "notify" { channel channel text "Vehicle {item.id} overdue" }
  }
}

Expressions have a string toolkit usable anywhere a value is — upper, lower, trim, length, substring, replace, concat, split, join:

for records where upper(substring(attr "vin", 0, 3)) == "1FT"

…and a date toolkit — now(), date(s), days_until(d), days_between(a, b) — that complements the today keyword and date ± N units arithmetic already in the evaluator. days_until/days_between return a number, so they drive ordinary numeric guards; now/date/today are date values that stringify ISO, so they drop cleanly into a query window:

for records where days_until(attr "due_on") <= 7        // due within a week
  and attr "due_on" >= today                            // and not already overdue

// build a relative date window for a list-tool query argument:
query concat("due_on:[", today, " TO ", today + 7 days, "]")

The string toolkit is mirrored in the JavaScript reactive runtime (packages/runtime) — the client-side engine for reactive rules stays in step with the Go compiler.

Metaprogramming — compile-time macros

Status: the compile-time expansion phase is merged (internal/macro, ADR 0011) — today an identity transform. The defmacro/quote/unquote grammar below is accepted design, not yet implemented, so you can't write a macro just yet — but the ordinary blocks a macro expands into (shown below) are valid tln today (verified with tln build).

tln does metaprogramming the Elixir way: macros are code that writes code, and they run at compile time. A defmacro expands into ordinary blocks before validation and planning — the runtime never sees a macro, so the engine stays exactly as deterministic and terminating as always. The one place unbounded computation is allowed is expansion itself, which is bounded by a step budget (a compile error, never a runtime hang).

This is why metaprogramming lives in core, not a plugin: only core owns the grammar and the compile phases. (Runtime "code-as-data" over Prolog terms is a different thing — that belongs to the tln-prolog engine, which brings its own term structure.)

quote turns a block into an AST value; unquote splices a value in; defmacro is a compile-time function from arguments to AST. A macro that kills boilerplate across near-identical detect rules:

defmacro over_threshold(name, metric, limit, prio) {
  quote {
    detect "High {unquote(name)}" {
      for records where type == "item" and attr unquote(metric) > unquote(limit)
      flag matching items
      label "{item.name}: high {unquote(name)}"
      priority unquote(prio)
    }
  }
}

over_threshold("temperature", "temp_c", 80, HIGH)
over_threshold("pressure",    "psi",   200, MEDIUM)

expands at compile time into two ordinary detect blocks — all the validator, planner, and runtime ever see:

detect "High temperature" {
  for records where type == "item" and attr "temp_c" > 80
  flag matching items
  label "{item.name}: high temperature"
  priority HIGH
}
detect "High pressure" {
  for records where type == "item" and attr "psi" > 200
  flag matching items
  label "{item.name}: high pressure"
  priority MEDIUM
}

Because a macro emits nothing but ordinary AST, everything downstream — explainability, testing, the reactive runtime — treats generated rules identically to hand-written ones. That includes tool calls: a macro can splice tool "audit" "writeln" { … } into every rule it generates, so effect boilerplate is generated too (see ADR 0012).

Expert-in-the-Loop

Traditional AI systems use human-in-the-loop — a human reviews every AI decision. This doesn't scale. tln introduces expert-in-the-loop — a deterministic expert system that collaborates with the LLM in real time.

graph LR
    USER([User]) --> LLM["LLM<br>(conversation, intent,<br>natural language)"]
    LLM <--> TLN["tln Expert System<br>(facts, inference,<br>policy, predictions)"]
    TLN <--> FACTS[(FactStore)]
    LLM --> RESPONSE([Response])
    TLN --> |"proactive<br>alerts"| RESPONSE

    style LLM fill:#faf5ff,stroke:#a855f7
    style TLN fill:#f0fdf4,stroke:#22c55e
    style FACTS fill:#fffbeb,stroke:#f59e0b

How they collaborate:

Situation LLM does tln does
User asks about an item Understands intent, picks the right tool Enriches response: "Note: this item is 5,000 km overdue for service"
User wants to delete something Prepares the tool call Policy check: blocks if user lacks permission
Nothing was asked Nothing (reactive only) Detects a pattern in the background, surfaces it proactively
tln detects a failure risk Drafts the alert message in the user's language Ran the prediction, computed the confidence
User asks "why?" Explains in natural language Provides the trace: which facts, which rule, which threshold

The LLM is good at language. tln is good at logic. Neither replaces the other.

Inside OpenTalon

When tln runs as a plugin inside OpenTalon, the expert-in-the-loop pattern integrates at three points:

User message arrives
  |
  v
[1. tln as preparer]
  |  Evaluates rules against matched tools.
  |  Known patterns → execute directly (skip LLM).
  |  Unknown → pass through to LLM.
  |
  v
[2. LLM agent loop]
  |  Every tool result → asserted into tln's FactStore.
  |  Before each tool call → tln policy check (block/allow).
  |
  v
[3. tln post-execution]
     Evaluates detect/predict/forecast over accumulated facts.
     Appends proactive insights to the response.

More Examples

Policy enforcement
rule "Regional data restriction" {
  when tool_action starts_with "inventory"
    and tool_arg "org_unit_id" not in context.allowed_org_units
  block reason "You don't have access to this organisational unit"
}

rule "Certification required for heavy equipment" {
  for records where category in category_tree("Heavy Machinery")
  before "assign"
    when target_person attr "safety_cert_expires" < today
  block "assign"
  reason "{person.name}'s safety certification expired"
}
Temporal patterns

Ordered sequences across records (A followed_by B [on same KEY] within N units) flag entities whose history matches a chain, not just a point-in-time shape:

detect "Engine failure chain" {
  for records where type == "vehicle"
    and record type "electrical_fault"
        followed_by record type "engine_failure"
        on same item within 30 days
  flag matching items
  label "{item.name}: electrical fault preceded engine failure"
  priority HIGH
}

event_sequence "A" -> "B" -> "C" within N days is the same idea for streams of :event/... facts (e.g. cart-abandonment funnels). Both compile to in-process matchers — no extra service required.

Anomaly detection
detect "Unusual consumption" {
  for records where type == "stock_item"
    and attr "weekly_consumption" is anomaly
    compared_to last 12 weeks
  flag matching items
  label "{item.name}: {attr.weekly_consumption} this week (normally ~{avg})"
  priority HIGH
}
Vector similarity (HNSW)

find similar can route through a per-scope HNSW index when the rule names a vector scope. Each tenant can hold multiple embedding models side-by-side — dimension is locked on first insert into a scope so a 384-dim model never collides with a 1536-dim one:

find similar "Find related vehicles" {
  for records where type == "vehicle"
  to 1
  using vector scope "embed3"
  top 5
  within 0.3
}

The executor reads the seed's :vector/<scope> fact, asks the store for top+1 neighbours, drops the seed, applies within as a metric-distance threshold, and narrows the candidate set to the surviving ids. The HNSW index itself is served by the tln-db backend, which is packaged as a plugin (see opentalon/tln-db); with the memory/datalevin stores, find similar needs a store that provides the vector scope.

Failure prediction
predict "Equipment failure risk" {
  for records where type == "item" and status == "active"
  features [
    attr "operating_hours",
    attr "age_days",
    attr "repair_count_last_year",
    attr "category"
  ]
  trained_on records where status changed_to "defective"
  confidence >= 0.7
  label "{item.name}: {confidence}% failure risk in next 30 days"
  priority HIGH
}
Workflow with MCP calls
workflow "Onboard new team member" {
  step "create_person" {
    tool "hr" "create-person" {
      first_name context.first_name
      last_name context.last_name
      org_unit_id context.org_unit
    }
  }

  step "assign_equipment" depends_on "create_person" {
    tool "inventory" "assign-item" {
      item_id context.laptop_id
      person_id step("create_person").result.id
    }
  }

  step "notify" depends_on ["create_person", "assign_equipment"] {
    tool "notifications" "send" {
      channel context.manager_channel
      message "{context.first_name} onboarded. Equipment assigned."
    }
  }
}
Testing
// maintenance.tln.test

test "Overdue service is detected" {
  given {
    record 501 type "item" category "Vehicles" status "active"
    attr 501 "km" 45000
    attr 501 "last_service_km" 20000
    attr 501 "name" "Truck A"
  }

  when detect "Service overdue"

  expect {
    flagged 501
    label contains "Truck A"
    priority == HIGH
  }
}

test "Up-to-date service is not flagged" {
  given {
    record 502 type "item" category "Vehicles" status "active"
    attr 502 "km" 25000
    attr 502 "last_service_km" 20000
  }

  when detect "Service overdue"

  expect {
    not flagged 502
  }
}

Tooling

Tool What it does
tln build Compile .tln files, report errors
tln test Run .tln.test files (supports -run NAME, -v, --junit FILE, dir walk)
tln repl Interactive REPL — assert facts, evaluate rules, trace execution
tln trace Step-by-step evaluation trace for debugging
tln mod Package manager (init, add, tidy, verify)

Editor support

Syntax highlighting + file detection for .tln and .tln.test files:

Editor Plugin Install
Vim / Neovim opentalon/tln-vim Plugin 'opentalon/tln-vim' (Vundle), Plug 'opentalon/tln-vim' (vim-plug), or git-clone into pack/*/start/ (Neovim native)
VS Code opentalon/tln-vscode git clone https://github.com/opentalon/tln-vscode ~/.vscode/extensions/opentalon.tln-vscode-0.1.0 then reload

Both plugins mirror the keyword list in internal/lexer/lexer.go, so block headers, ML primitives, template interpolations ({item.name}), priorities, and comments all colour correctly out of the box.

A future LSP server (autocomplete, on-save diagnostics, go-to-definition) will work across both editors; tracked in issue #18.

Roadmap

Language and Vision
Architecture
Compiler
Ecosystem

References

License

Apache 2.0 — see LICENSE.

Directories

Path Synopsis
cmd
tln command
internal
actions
Package actions resolves the `do` clauses of a rule into the action payload the engine hands back to its host.
Package actions resolves the `do` clauses of a rule into the action payload the engine hands back to its host.
ast
constraints
Package constraints enforces integrity-constraint blocks against incoming facts.
Package constraints enforces integrity-constraint blocks against incoming facts.
defeasible
Package defeasible resolves conflicts between rule blocks that match the same target.
Package defeasible resolves conflicts between rule blocks that match the same target.
explain
Package explain produces user-facing "why did this fire" explanations for tln decisions.
Package explain produces user-facing "why did this fire" explanations for tln decisions.
factstore
Package factstore is tln's database abstraction.
Package factstore is tln's database abstraction.
gen
Package gen renders tln AST nodes back into canonical .tln source.
Package gen renders tln AST nodes back into canonical .tln source.
imports
Package imports resolves `import "./path"` directives in a parsed tln program.
Package imports resolves `import "./path"` directives in a parsed tln program.
log
Package log is the runtime observability surface for tln.
Package log is the runtime observability surface for tln.
macro
Package macro is tln's compile-time macro-expansion phase (ADR 0011).
Package macro is tln's compile-time macro-expansion phase (ADR 0011).
mlmodel
Package mlmodel is the shared representation and resolver for named ML models (issue #13 ML-module system).
Package mlmodel is the shared representation and resolver for named ML models (issue #13 ML-module system).
mlruntime
Package mlruntime executes the 7 ML primitive keywords described in ADR-0001.
Package mlruntime executes the 7 ML primitive keywords described in ADR-0001.
mod
Package mod parses the tln project manifest, `mod.tln` — the Bundler-style declaration of which plugins a project uses (ADR 0013).
Package mod parses the tln project manifest, `mod.tln` — the Bundler-style declaration of which plugins a project uses (ADR 0013).
optimize
Package optimize implements multi-objective optimization primitives for tln's `combine` block.
Package optimize implements multi-objective optimization primitives for tln's `combine` block.
reactive
Package reactive routes FactStore events to matching `on` blocks.
Package reactive routes FactStore events to matching `on` blocks.
repl
Package repl implements `tln repl` — an interactive read-eval-print loop that lets users assert facts, define blocks inline, and evaluate them against an in-memory store.
Package repl implements `tln repl` — an interactive read-eval-print loop that lets users assert facts, define blocks inline, and evaluate them against an in-memory store.
template
Package template renders ast.Template values against a runtime RenderContext.
Package template renders ast.Template values against a runtime RenderContext.
pkg
arith
Package arith is the shared numeric kernel for the tln ecosystem.
Package arith is the shared numeric kernel for the tln ecosystem.
factstore
Package factstore is the public backend SPI for tln.
Package factstore is the public backend SPI for tln.
tln
Package tln is the public Go SDK for the tln language.
Package tln is the public Go SDK for the tln language.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL