𧬠LAZARUS
The cure may already be on the shelf. We just never connected the two nodes.
A graph-native drug repurposing engine for rare disease, written in Jac.
π Submitted to Social Impact Β· also in the running for Best Use of Jac

π The problem
There are about 7,000 rare diseases. Roughly 95% of them have no approved treatment.
Not because the science is impossible β because the market isn't there. A disease with 400 patients worldwide will never justify a billion-dollar development programme. So nobody starts one, and the disease stays untreated forever.
Meanwhile there are ~20,000 drugs already approved by the FDA. Every one of them is manufactured, dosed, safety-tested, and sitting in a pharmacy right now β for something else.
Sometimes one of them already works.
In 2012 a physician-scientist was dying of idiopathic multicentric Castleman disease. Out of options, he traced his own disease through its biology β iMCD activates mTOR β to sirolimus, a drug approved in 1999 for organ transplant rejection. He started taking it. He has been in remission for over a decade.
Sirolimus had been on pharmacy shelves the entire time he was dying. Nobody had connected the two nodes.
π― LAZARUS is a search engine for that connection.
πΈοΈ The insight: this is a graph problem, not a text problem
A repurposing hypothesis is not a document to summarise. It is a path:
Disease ββImplicatesβββΆ Gene ββParticipatesβββΆ Pathway βββModulatesββ Drug
If a path exists from a disease with no treatment to a drug that already exists, that path is the hypothesis. Finding it is graph traversal β which is precisely what Jac was built for.
So we didn't build a chatbot over a corpus. We built the graph, and we let a walker walk it.
β¨ What it does
- π― Pick a rare disease β Castleman, Progeria, LAM, Niemann-Pick C, FOP, or ALS.
- π Release the walker. It starts on the disease node and moves outward through genes, into pathways, and back out to every already-approved drug that touches that biology β relaxing a multiplicative confidence score at every hop.
- ποΈ Watch it happen. The animation is not a re-enactment. It is the walker's own
hopslist, replayed in traversal order. What you are looking at is the program running. - π§Ύ Get a ranked list with provenance. Every candidate shows the full chain it came from and the citation on every edge it crossed.
- π€ Click any drug for a mechanism brief β thesis, why it could hold, the most likely reason it fails, and the cheapest experiment that would falsify it. Generated with
by llm()into an enforced schema.
π§ Two design decisions we're proud of
It subtracts what's already known. Siltuximab is already approved for Castleman disease. It scores highest β and the engine sets it aside, because standard of care is not a discovery. Only the untried paths are ranked.
It grades its own homework. A handful of repurposings that really happened are stored as ground truth. The engine is never told about them during search β they're attached afterwards. On Castleman disease, the traversal surfaces tocilizumab at #1 and sirolimus at #2, both real, historically validated repurposings. That's the argument that the untested candidates below them are worth an afternoon.
We also kept a failure in the ground truth. Ceftriaxone reached phase 3 in ALS on exactly the rationale this engine produces, and missed its endpoint. A scoring engine that hides its misses isn't worth trusting.
π· Why Jac β and why this project couldn't be a Python app
This is not "a Python project with Jac syntax." Four Jac language features carry the architecture:
1. node / edge / walker β the domain is the graph
Genes, pathways and drugs are node archetypes. Evidence lives on typed edge archetypes. There is no ORM, no adjacency table, no graph library. The traversal reads like the biology:
can on_pathway with Pathway entry {
# Drugs point *into* the pathway, so this hop reads the incoming edges.
for d in [here <-:Modulates:<-] {
links = [edge d ->:Modulates:-> here];
if self.relax(here, d, base * links[0].weight, "modulates", ...) {
visit d;
}
}
}
2. Walkers are the animation
The walker records its own itinerary as it moves. The frontend replays that list. This is Jac's topokinetic idea made literally visible: computation moving through a topology of data. The picture on screen is the execution trace.
3. by llm() with sem β there is not one prompt string in this repo
def draft_mechanism(disease: str, drug: str, gene: str, pathway: str,
evidence: list[str], confidence: str) -> Mechanism
by llm(temperature=0.2);
sem Mechanism.biggest_risk = "One or two sentences naming the single most likely
reason this hypothesis fails β off-target toxicity, tissue penetration,
redundancy in the pathway, or weak causal evidence for the gene.";
The signature is the specification and the return type is the enforced schema, so the UI addresses .biggest_risk directly instead of parsing a paragraph. The prompt cannot drift from the code, because it is the code.
4. One language, all three tiers
walker:pub makes a walker a REST endpoint. The browser calls it with root spawn Repurpose(disease="imcd") β a server walker spawned from client code. The HTTP request, the serialisation and the shared types are compiler output. The UI is cl Jac compiling to React. There is no fetch and no API client in this repository, because there was nothing to write.
The graph persists under root automatically. Restart the process; the knowledge graph is still there. No migrations, no schema file.
πΌοΈ Screenshots
The dormant graph β everything we know, unlit:

The mechanism brief, typed straight out of by llm():

π Run it
pip install jaclang byllm jac-client # needs Python 3.12+
jac run # β http://localhost:8000
Optional β for model-written briefs instead of the deterministic fallback, drop a .env in the repo root (see .env.example):
LAZARUS_BASE_URL=https://api.openai.com/v1
LAZARUS_API_KEY=sk-...
LAZARUS_MODEL=gpt-4o-mini
Any OpenAI-SDK-compatible endpoint works β OpenAI, Groq, OpenRouter, Together, vLLM, LM Studio, Ollama's compat shim, or an internal gateway.
It runs with no API key. explain() falls back to a brief assembled from the same graph evidence, so a missing key, a rate limit or dead conference wifi degrades the demo instead of ending it. The brief panel always shows which path produced it, so a silent fallback can never masquerade as a working model.
Want to rehearse the AI path with no key at all? LAZARUS_MODEL=mockllm jac run exercises the real by llm() code path against a built-in mock.
π Full setup, demo script and troubleshooting: DEPLOY.md
βοΈ One environment quirk we hit On our machine, hot-reload after editing a `.jac` file could fail with `Native compilation failed: create_pipeline_tuning_options() got an unexpected keyword argument 'size_level'` β an `llvmlite` version mismatch in the HMR path. Cold starts are unaffected: stop the server and re-run `jac run`.ποΈ How the code is laid out
| File | What it does |
|---|---|
kg.sv.jac |
Node & edge archetypes, and the server-side layered layout |
seed.sv.jac |
The curated knowledge graph β 52 nodes, 57 evidenced edges, plus ground-truth repurposings |
engine.sv.jac |
π« RepurposeSearch β the walker, the score relaxation, the ranking |
ai.sv.jac |
Mechanism schema, sem annotations, by llm(), and the offline fallback |
endpoints.sv.jac |
Three walker:pub REST endpoints |
env.sv.jac |
Dependency-free .env loader and model resolution |
frontend.cl.jac |
The app shell β state, mount, walker calls |
components/GraphCanvas.cl.jac |
The traversal visualisation, in Jac JSX |
assets/main.css |
Design system |
β οΈ What this is not
LAZARUS generates hypotheses, not prescriptions. It is a prioritisation tool for researchers, not clinical decision support, and nothing here should reach a patient without a trial.
Honest limitations, stated plainly:
- π¬ The graph is hand-curated, not comprehensive. 52 nodes across 6 diseases. We chose defensible edges over scraped volume β a repurposing claim is only worth the evidence on the edge that produced it. Scaling means ingesting Open Targets and Reactome in full, which is an engineering problem, not a research one.
- π The score is a heuristic, not a probability. It is the product of curated edge confidences and should be read as a ranking, not a likelihood.
- π§ Four hops only. Real repurposing sometimes needs longer or stranger paths than
disease β gene β pathway β drug.
The validated hits are what make the ranking credible. The rest is a starting point for someone with a lab.
π Why we built it
Every one of the 52 nodes in this graph stands for people who are waiting. For most of them, no company will ever start a programme β the arithmetic doesn't work.
But the drug might already exist. It might already be approved, already be manufactured, already be in the pharmacy down the street, waiting for someone to draw a line between two nodes.
That line is a graph traversal. So we wrote the walker.
Built at JacHacks SF 2026 with Jac π₯
Log in or sign up for Devpost to join the conversation.