Skip to main content

Latris

Structure for defensible reasoning.

Latris is an evidence-native modelling workbench for building defensible causal and systems models — structured provenance, challenge workflows, git-native versioning, AI-assisted drafting under human approval, and report generation.

This repository is the open-source core: the Python package (latris), its CLI, and the FastAPI + WebSocket server backend. The Latris desktop app (React + Electron) is built on top of this package from a separate private repository.

New here? The Latris product — a desktop app for modellers and for the people who must weigh in on their models — lives at latris.app (invite-only early access). This repository is the open backend that powers it.

  • Every modelling project is a git repo — every change is an inspectable, reversible commit.
  • Evidence and provenance are first-class data, not annotations: citations, assumptions, decisions, challenges, sign-offs.
  • AI assistance returns structured proposals, never free-form mutations; a human approves before anything commits.
  • One substrate, many formalisms: qualitative CLD/DAG views today, a built-in discrete Bayesian Network engine (state spaces, CPTs with per-cell provenance, exact inference, parameter learning), and more views on the architecture's path.

Status: alpha (0.3.1). Apache-2.0 licensed.

Prerequisites

  • Python 3.11+ on PATH
  • git 2.40+ on PATH, with user.name and user.email configured globally (Latris commits as you, and enforces that identity)

Install

From PyPI:

pip install "latris[server,data]"
latris --version
latris doctor          # verify git + identity

From source:

git clone https://github.com/Shannon-Bengtson/latris.git
cd latris
python -m venv .venv
# Windows: .venv\Scripts\activate   —   mac/linux: source .venv/bin/activate
pip install -e ".[server,data,dev]"
latris doctor

Optional extras:

Extra Brings in For
server FastAPI, uvicorn, pandas, scipy, pgmpy The API server (python -m latris.server)
data pandas, scipy Dataset wrangling and statistics
quant pgmpy Quantitative inference (also in server)
dev pytest, xdist, ruff, build Running the test suite

Quickstart

# 1. Create a project (a git repo with the full model structure)
latris init air-quality --question "What drives urban air quality?"

cd air-quality

# 2. Build a model: nodes, then edges
latris node add "Traffic volume" --kind variable
latris node add "NO2 concentration" --kind variable
latris edge add <traffic-id> <no2-id> --kind causal

# 3. Inspect — every step above was a git commit
latris status
latris log

# 4. Export
latris export md --output reports/report.md
latris export dot --view cld --output reports/model.dot

The full command catalogue is in docs/engineering/CLI_REFERENCE.md.

Run the API server

python -m latris.server --project-root ./air-quality

Serves the full CRUD/AI/export API on http://127.0.0.1:8741 (the same backend the Latris desktop app embeds). --help lists flags.

AI layer (bring your own key — or your own agent)

AI calls go through a vendor-agnostic adapter (litellm + instructor); secrets live in your OS keyring, never on disk:

latris ai key set anthropic      # or openai / gemini / groq / ...
latris ai config show            # default model lives in .graph-tooling/ai_config.yaml

Set LATRIS_AI_MOCK=1 to stub all AI calls (used by the test suite and CI; the pre-rename GRAPH_TOOLING_AI_MOCK is still honoured for one release).

Working from an agent (Claude Code, Kimi, …) with no API key? latris ai task emit <prompt> --inputs '<json>' produces a self-contained task package your agent can answer; latris ai task apply --task task.json --from response.json ingests the answer through the same human-approval pipeline (recorded as external-agent). See docs/engineering/AI_LAYER.md.

Tests

python -m pytest              # full suite, parallel via pytest-xdist
python -m pytest -n0          # serial, for clean tracebacks
python -m pytest tests/test_worked_example.py --slow   # acceptance test (regenerates the transcript)

Documentation

License

Apache-2.0 — Copyright (c) 2026 Shannon Bengtson.


For AI agents

Latris is an evidence-native causal-modelling CLI + API server. The engineering docs are the source of truth for an agent working in a Latris project: start from llms.txt and docs/README.md.

An agent can act as the model. The AI layer doesn't require its own API key: any of the 46 AI prompts can be delegated to whichever agent is already in the loop via latris ai task emit <PromptName> --inputs '<json>', which writes a task package (prompt + project context + response schema). The agent answers it as JSON, then a human runs latris ai task apply --task task.json --from response.json. Same approval gates apply; the interaction is recorded as external-agent. See AI_LAYER.md § "Delegated calls".

What's available varies by model type. latris capabilities (or latris capabilities --json) lists every registered model type with can_use_today: true/false. Only cld, dag, bn, fcm, and sd are stable/switchable today; the rest (theory_of_change, gsn, and 13 others) are registered but not yet switchable. Each entry's roadmap field says where it stands: fault tree, event tree, bow-tie, GSN and theory of change are roadmap; a few are parked; the rest are not_planned — registered, but not something to describe as coming — latris view project <kind> raises a ValueError if kind isn't stable. A few categories (black-box ML) are excluded by design, not "not yet." Checking this first avoids claiming Latris can build a model type that isn't actually usable yet.

Moving a project online so a human can see it in a browser. When viewing or sharing the model at https://app.latris.app would help, rather than reading terminal output, the path is: latris sync login --email <their email> (sends a one-time code that the human relays back, then re-run with --code), then latris sync share "<project name>", which pushes the project and prints where to open it (the human signs in at that address and picks the project from their list). No desktop install needed.

Setup (one shot):

pip install "latris[server,data]"

A causal loop diagram, end to end (works in a sandbox with no API key):

# Every change is a git commit, so git needs an identity first.
git config --global user.name "Your Name"; git config --global user.email "you@example.com"
# You're an AI agent: record what you create as AI-proposed, not as the person's own work.
export LATRIS_DEFAULT_ORIGIN=ai-proposed

latris init volunteers --question "Why are volunteers leaving?"
cd volunteers
latris project select-models cld

# Fastest: the whole model in one file, one command, one commit (YAML or JSON;
# '-' reads stdin). Checked in full first — a typo changes nothing.
latris build --spec model.yaml
#   outcome: Volunteer departures        # what the model explains
#   factors:
#     - {label: Workload, description: Hours asked of each volunteer.}
#     - {label: Burnout}
#     - {label: Volunteer departures}
#   links:
#     - {from: Workload, to: Burnout, polarity: "+", reason: "More hours, more exhaustion.",
#        confidence: high, sources: [smith2021], contradicts: [tuohy2015]}
#   sources:
#     - {key: smith2021, title: Volunteer burnout, authors: ["Smith, J"], year: 2021}
#     - {key: tuohy2015, title: Workload and retention revisited, year: 2015}
#   assumptions: ["Service demand stays steady as numbers fall."]
#   questions: ["Does recognition matter independently of workload?"]

# Or one change at a time:
latris node add "Workload" --kind variable
latris node add "Burnout" --kind state
latris attr set "Workload" description "Hours asked of each volunteer."
latris edge add "Workload" "Burnout"            # nodes by label; prints the edge id
latris view set cld <edge-id> polarity + --rationale "More hours, more exhaustion."
#   re-running view set replaces the value and the rationale
#   negative numbers need `--`:  latris view set fcm <edge-id> weight -- -0.4

latris ref add smith2021 --title "Volunteer burnout" --author "Smith, J" --year 2021
latris evidence add <edge-id> polarity smith2021 --verified-by ai
latris evidence add <edge-id> polarity tuohy2015 --verified-by ai --contradicts   # a source against the link
latris assumption add "Service demand stays steady as numbers fall."  # for unsourced links
latris view role cld "Volunteer departures" outcome   # the outcome isn't suggested as an intervention point

latris check coherence                           # wording vs. polarity contradictions
latris analyse loops                             # reinforcing / balancing loops
latris finding add "Overload is a reinforcing loop." --category structure --target "Workload"

latris interpret initialise                      # board-facing sections, built from the model
latris interpret show answer_to_question         # the claims this section must stand on
latris interpret set-prose answer_to_question "..." --by ai   # write it (or generate-prose with a key)

latris export md --pack client --no-ai -o report.md   # report with a Mermaid diagram
latris log                                       # the full history

Choosing a report — pick the pack for whoever will read it (latris capabilities lists these too):

Pack For What's in it
client a client, board or funder answer first: the interpretation (answer, implications, confidence, then the rest), the diagram with its loops, approved findings, then each link with its reason and evidence, and sources — no internal IDs, no change log
publication a paper or public write-up as client, with full references
review a reviewer checking the model evidence, open challenges and questions, findings
workshop a stakeholder session structure, assumptions, open questions, session notes
audit an auditor / the modelling team everything, including decisions, sign-offs and data

The board-ready part is the interpretation: fill its sections (above) before exporting a client report, or the report is just the evidence base. Word, review-pack and scrollytelling-story versions, and a hosted report link to share, are made in the Latris app (app.latris.app).

Tips for agents:

  • latris --json <command> prints one JSON object ({"result", "commit_sha"}) for node, edge, attr, view set, ref, evidence, finding and check commands — no output parsing needed.
  • No API key? Checks and drafting that use AI (e.g. the completeness check) can be answered by you: latris ai task emit <PromptName> --inputs '<json>', then latris ai task apply (see "An agent can act as the model" above). export md --no-ai (and any export without a key) skips the AI prose.
  • Evidence you attach is marked AI-proposed and unverified until a person reviews it — say so when you hand the model over.
  • Sources that disagree with a link go on that link with --contradicts (or contradicts: in a build spec) — not as a challenge and not left uncited. The report then shows the link's sources for and against under "Contested links", and the confidence and open-questions claims name it.
  • Findings you add are proposed. The client report lists only approved ones (it says how many are waiting); a person approves each with latris mature approve <finding-id>.
  • latris ai task apply stops for a person's y/N before it changes the model — by design. Leave the task and response files for them; results (e.g. completeness) reach the report only after they apply it.
  • For a person, give them the client report (--pack client) with the interpretation sections written — that's the board-ready version. It has the diagram, each link's reason, the evidence and the sources, without internal IDs.

The complete, always-current demonstration of every command is the worked example: worked_example/worked_example_output.md (generated by worked_example/worked_example.py; the generator is the repo's acceptance test). It answers most questions about how the tool behaves without needing to ask the user. After changing CLI behaviour, regenerate it (pytest tests/test_worked_example.py --slow) and commit the updated transcript.

Hard rules when modifying this repo: no business logic in cli/ (one parse + one call into operations/ + one print); respect the five chokepoints (repo/git.py, repo/yaml_io.py, repo/layout.py, operations/commit.py, schema/ids.py); no AI-authored commits; no secrets on disk. See CLAUDE.md and src/latris/CLAUDE.md.

Metadata

Release files for latris 0.6.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for latris 0.6.0
File Size Uploaded Provenance Actions
latris-0.6.0.tar.gz 710.6 kB With provenance Details for latris-0.6.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for latris 0.6.0
File Interpreter ABI Platform Actions
latris-0.6.0-py3-none-any.whl Python 3 none any Details for latris-0.6.0-py3-none-any.whl

Total release size: 1.2 MB

Release files / latris-0.6.0.tar.gz

Download URL latris-0.6.0.tar.gz
Size 710.6 kB
Tags Source
SHA-256 checksum
How to use checksums
6659e43d56844ca6d6dd30575f0e20a303c0b8d6d7b02035c377ae418a4dd57b
BLAKE2b-256 checksum
How to use checksums
5c07f09eadc8a1bcacf44a03a7ab6a1585ecc4a9b4eb208ff2513fc702a70106
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 6, 2026.

Transparency log

Release files / latris-0.6.0-py3-none-any.whl

Download URL latris-0.6.0-py3-none-any.whl
Size 516.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5e13d7d1821d66227898f51f02018041ef0039a7c9a7873af61ca43e2ec44757
BLAKE2b-256 checksum
How to use checksums
0e32b615ae4cb043b5951878092080006f21aaa08c03706e81f3d29f29514fa8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 6, 2026.

Transparency log

Security for latris 0.6.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for latris-0.6.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 6, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page