Metadata-Version: 2.5
Name: latris
Version: 0.5.0
Summary: Latris — an AI-assisted, evidence-native causal-modelling workbench (Python CLI + server backend).
Project-URL: Homepage, https://latris.app
Project-URL: Repository, https://github.com/Shannon-Bengtson/latris
Author: Shannon Bengtson
License: Apache-2.0
License-File: LICENSE
Keywords: bayesian,causal,cld,evidence,git,latris,modelling,provenance,systems-thinking
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: MacOS
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: OS Independent
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering
Classifier: Topic :: Scientific/Engineering :: Visualization
Requires-Python: >=3.11
Requires-Dist: bibtexparser<2,>=1.4
Requires-Dist: click>=8.2
Requires-Dist: httpx>=0.28
Requires-Dist: instructor>=1.3
Requires-Dist: keyring>=25
Requires-Dist: litellm>=1.40
Requires-Dist: pint>=0.24
Requires-Dist: pydantic>=2.6
Requires-Dist: python-ulid>=2.2
Requires-Dist: rich>=13.7
Requires-Dist: ruamel-yaml>=0.18
Requires-Dist: simpleeval>=1.0
Requires-Dist: typer>=0.26
Provides-Extra: data
Requires-Dist: pandas>=2.0; extra == 'data'
Requires-Dist: scipy>=1.11; extra == 'data'
Provides-Extra: dev
Requires-Dist: build>=1.2; extra == 'dev'
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
Requires-Dist: pytest-rerunfailures>=14; extra == 'dev'
Requires-Dist: pytest-xdist>=3.5; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.4; extra == 'dev'
Provides-Extra: quant
Requires-Dist: pgmpy>=1.1; extra == 'quant'
Provides-Extra: server
Requires-Dist: fastapi>=0.115; extra == 'server'
Requires-Dist: pandas>=2.0; extra == 'server'
Requires-Dist: pgmpy>=1.1; extra == 'server'
Requires-Dist: python-multipart>=0.0.7; extra == 'server'
Requires-Dist: scipy>=1.11; extra == 'server'
Requires-Dist: uvicorn[standard]>=0.34; extra == 'server'
Requires-Dist: watchfiles>=1.0; extra == 'server'
Description-Content-Type: text/markdown

# 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](https://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:

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

From source:

```bash
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

```bash
# 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`](docs/engineering/CLI_REFERENCE.md).

## Run the API server

```bash
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:

```bash
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](docs/engineering/AI_LAYER.md).

## Tests

```bash
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

- [`docs/README.md`](docs/README.md) — documentation index
- [`docs/engineering/ARCHITECTURE.md`](docs/engineering/ARCHITECTURE.md) — how it's built
- [`docs/engineering/CLI_REFERENCE.md`](docs/engineering/CLI_REFERENCE.md) — command catalogue
- [`worked_example/worked_example_output.md`](worked_example/worked_example_output.md) — a full end-to-end session transcript
- [`llms.txt`](llms.txt) — machine-readable doc map for AI agents

## License

[Apache-2.0](LICENSE) — 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`](llms.txt) and
[`docs/README.md`](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](docs/engineering/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):

```bash
pip install "latris[server,data]"
```

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

```bash
# 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

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 assumption add "Service demand stays steady as numbers fall."  # for unsourced links

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 | the model and diagram, the reason and evidence behind each link, findings, the **interpretation** (answer, implications, confidence, open questions) and sources — no internal IDs |
| `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.
- **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`](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`](CLAUDE.md) and
[`src/latris/CLAUDE.md`](src/latris/CLAUDE.md).
