Open source / Lachesis

Lachesis

A compiler-precise code property graph you can ask questions about: how data moves, who calls what, and what reaches a dangerous sink. It parses C, Python, TypeScript and JavaScript with real compilers, not regexes, and serves the whole graph to you or an AI agent over MCP.

AGPL-3.0 Written in Python Analyzes C · Python · TS · JS MCP server Complete local installer

A 55-second walkthrough: a Flask control plane where three handlers reach the same SQL call unguarded while two sibling handlers authorize first. Lachesis follows the value, flags the three, and names their guarded twins, posted inline on the pull request.
See it live on the pull request →

Why it exists

Most code-graph tools stop at symbols and references. That tells you where a name appears. It cannot tell you how a value moves, and that gap is where the interesting questions live. Does this request parameter reach that SQL call? Which of two near-identical functions checks its input before the lookup, and which one does not? What can flow into this buffer?

Lachesis is built around the answer. Its dataflow edges, value-flow, points-to, taint and aliasing, alongside resolved and possible call edges, let a tool reason about reachability and tainted flow instead of pattern-matching text and hoping. And because it parses with the language's own compiler, it answers from the parse, not the spelling.

What you can do with it

A graph you query, not a report you read.

Real compilers, not regexes

Parses with the language's own compiler, so it never loses a caller to a rename, an alias, or an import indirection. It answers from the parse, not the spelling.

A full dataflow layer

Value-flow, points-to, taint and aliasing edges, so you can ask about reachability and tainted flow, not just where a symbol appears.

One graph, four languages

C, Python, TypeScript and JavaScript in a single graph, stored in an embedded columnar database that opens in well under a second.

Built for agents

A small navigation API and an MCP server hand the graph to a person or an LLM, so an agent can reason over real source with compiler fidelity.

Confidence on every edge

Each edge states how sure it is and where it came from, so you can tell an exact fact from a safe over-approximation.

Security-shaped questions

Guard coverage, sibling comparison, and source-to-sink reachability are first-class, the questions a reviewer actually asks.

Quickstart

Use the complete installer for the model-backed local stack, or install the headless package when you only need CLI/MCP access. Both paths run locally and need no account.

git clone https://github.com/UnboundCompute/lachesis-ui
cd lachesis-ui
./scripts/install.sh
export PATH="$HOME/.lachesis/bin:$PATH"
~/.lachesis/build-graph.sh ./my-project     # build with the reviewed engine + catalog
lachesis-ui                                   # explore the graph

For a headless install, use pip install lachesis-cpg and point ATROPOS_ROOT at a reviewed Atropos checkout or installed model pack. The TUI installer is the shortest complete path.

See it work

Two sibling functions reach the same database call. One checks the caller's tenant first; the other does not. A symbol index sees both call findById and stops there. Lachesis tells them apart by following the value.

~/.lachesis/venv/bin/lachesis-analyze lachesis/frontends/typescript/fixtures/project example.kuzu
~/.lachesis/venv/bin/lachesis-query --format text example.kuzu overview
# overview
Project: layered-project
Languages: javascript, typescript
Canonical graph: 3307 nodes / 6078 edges
Security paths: 6
Guard differentials: 1

One guard differential: a pair of siblings reaching the same sink where one authorizes and one does not. Ask about the unguarded one:

lachesis-query --format text example.kuzu handler-security getDocument
"status": "UNGUARDED",
"guard_signal": null,
"differential_siblings": [ "getInvoice" ]

getDocument reaches findById with no check, and the record names its guarded twin, getInvoice, directly. That is the finding: a fact that lives in how the value moves, not where the name appears.

Run it in your CI

The same analysis on every pull request. lachesis-action builds the graph on your own runner, with no external service or API key, and writes findings straight into GitHub code scanning as inline annotations.

# .github/workflows/lachesis.yml
name: Lachesis
on: [pull_request]
permissions:
  security-events: write      # upload findings to code scanning
jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: UnboundCompute/lachesis-action@v1.0.5
        id: lachesis
        with:
          source: "."
          post-comments: "false"
          lachesis-ref: "v0.1.7"
          atropos-ref: "v1.7.1"
      - uses: github/codeql-action/upload-sarif@v3
        if: ${{ always() && steps.lachesis.outputs.sarif-file != '' }}
        with:
          sarif_file: ${{ steps.lachesis.outputs.sarif-file }}

Findings come back at three levels, the same distinctions the graph draws: errors for guard differentials, where one function authorizes a caller and a sibling reaching the same sink does not; warnings for unguarded sinks; and notes for guarded paths. It emits SARIF, so results land in the Security tab and as annotations on the diff. MIT licensed.

See it on a real pull request: five inline findings on a Flask control plane → — three guard-differential errors and two guarded notes, posted straight onto the diff.

Lachesis is the open code-property-graph engine that powers UnboundCompute, our hosted autonomous security researcher. Use it standalone, or let us run it at scale, tuned and adjudicated.

See the researcher →