Lesson 01

What is Scyla?

Scyla is a compiled programming language where the laws of biology, physics, and chemistry are not libraries you import. They are native opcodes the compiler already knows.

When you write half_life("dopamine") in Scyla, you are not calling a library function. You are calling a compiled opcode that returns the published pharmacokinetic half-life of dopamine: 1200 seconds. That number comes from peer-reviewed research. It is baked into the compiler binary.

Why Does This Matter?

Every programming language ever built treats biology as data. You import a CSV. You load a model. You write your own equations and hope you got the constants right.

Scyla treats biology as code. The Hodgkin-Huxley conductance equations that govern your neurons are the same equations that gate computation in Scyla. The pharmacokinetic decay that clears dopamine from your synapses is the same decay that governs state in a Scyla program.

The Key Insight

If the equations are published, peer-reviewed, and universal, why would you re-implement them every time? Make them native. Make them compiled. Make them impossible to get wrong.

What Can You Build With Scyla?

What You Don't Need

You do not need to know Rust. Scyla compiles to a Rust binary, but you never touch Rust code. You write .sy files. The compiler handles the rest.

You do not need a biology degree. The opcodes handle the science. You handle the logic and the governance.

You do not need to memorize constants. Every biological constant in Scyla is published and cited. The compiler knows them. You just call them.

What You Will Learn

By the end of these lessons, you will be able to write Scyla programs that use native biological opcodes, create temporal structs that evolve autonomously, and run governance compliance checks against your code.

The Name

In Greek mythology, Scylla guarded one side of a narrow strait. Sailors could not go around her. They had to pass through.

That is governance. You do not negotiate with the strait. You do not optimize around the monster. You submit to the passage, or you do not pass at all.

Scyla: the governance layer that is native to code.

Lesson 02

Installation

Scyla is distributed as a single binary. No dependencies. No virtual environments. No build tools. One file.

Step 1: Install via pip

Coming Soon

The Scyla compiler is not yet publicly available. It is currently undergoing internal review and audit before release. Join the waitlist at caelsereith@aetherprotocols.com to be notified when it launches.

Step 2: Verify Installation

$ scylac
scylac — The Scyla Compiler
Usage: scylac <command> <file.sy>

Commands:
  run <file>       Compile and run
  check <file>     Type check
  comply <rules> <file>   Governance check
  strip <file>     Remove native function names

Scyla: a language for systems that evolve over time.

If you see this output, you are ready to go.

Step 3: Create Your Project Folder

$ mkdir my-first-scyla
$ cd my-first-scyla

Scyla files use the .sy extension. In the next lesson, you will create your first one.

Note

Scyla is currently in early access. The pip package includes the compiler binary for Linux and macOS. Windows support is coming soon. If you are on Windows, you can use WSL (Windows Subsystem for Linux).

What Got Installed

The standard library includes 210+ native opcodes covering pharmacokinetics, physics, chemistry, organ physiology, genetics, immune function, clinical measurements, and more. You will learn about these in later lessons.

Lesson 03

Your First .sy File

Let's write a program. Create a file called hello.sy:

hello.sy scyla
// My first Scyla program
fn main() {
    print("Hello from Scyla.")

    // Let's use a native opcode
    let resting = tonic_drive("serotonin")
    print("Serotonin tonic firing rate:")
    print(resting)
}

Run It

$ scylac run hello.sy
Hello from Scyla.
Serotonin tonic firing rate:
0.2

That 0.2 is the published tonic firing rate of serotonergic neurons in the dorsal raphe nucleus: 0.20 Hz, from Aghajanian et al. (1982). You did not look it up. You did not type it. The compiler knows it.

What Just Happened?

  1. fn main() — every Scyla program starts here, just like C or Rust.
  2. print() — outputs text to the console.
  3. tonic_drive("serotonin") — a native opcode. Not a library call. This is compiled into the binary. It returns the published baseline firing rate for serotonin.
  4. let resting = ... — declares a variable. Scyla infers the type.
Native vs Library

In Python, you would write SEROTONIN_TONIC = 0.20 and hope you got the right number from the right paper. In Scyla, the compiler is the paper. The citation is embedded in the binary. You cannot get it wrong.

Try This

Modify your program to print the tonic drive for other neurotransmitters:

explore.sy scyla
fn main() {
    print("Tonic firing rates (published):")
    print("  Dopamine:")
    print(tonic_drive("dopamine"))       // 0.13 Hz (Grace & Bunney 1984)
    print("  Serotonin:")
    print(tonic_drive("serotonin"))     // 0.20 Hz (Aghajanian 1982)
    print("  Norepinephrine:")
    print(tonic_drive("norepinephrine")) // 0.50 Hz (Aston-Jones 1991)
    print("  GABA:")
    print(tonic_drive("gaba"))           // 0.10 Hz (Bhatt 2020)
}

These are the pilot lights of your nervous system. They never go to zero. Even in sleep, these neurons fire at their tonic rate. Scyla knows every one of them.

Congratulations

You just wrote a program that queries published neuroscience. In three lines. Without importing anything. Welcome to Scyla.

Lesson 04

Variables & Types

Scyla has a clean, familiar syntax. If you have written JavaScript, Python, or Rust, you will feel at home.

Declaring Variables

Use let to declare a variable. Scyla infers the type:

variables.sy scyla
fn main() {
    let name = "Scyla"            // String
    let version = 1.0             // Float
    let opcodes = 210             // Integer
    let is_compiled = true        // Boolean

    print(name)
    print(version)
    print(opcodes)
    print(is_compiled)
}

Constants

Use const for values that never change:

constants.sy scyla
const BODY_TEMP = 37.0        // Celsius. Physics. Not trainable.
const PH_BLOOD = 7.4          // Homeostatic setpoint

fn main() {
    print("Body temperature:")
    print(BODY_TEMP)

    // This would be a compile error:
    // BODY_TEMP = 38.0   // ERROR: cannot assign to const
}
const vs let

const values are immutable. They represent physics, universal constants, things that do not change. let values represent state, things that evolve. This distinction matters deeply in Scyla's temporal type system, which you will learn about in Lesson 7.

Basic Types

Math

math.sy scyla
fn main() {
    let cortisol = 0.8
    let half_life = 5400.0       // 90 minutes in seconds
    let elapsed = 2700.0        // 45 minutes

    // Manual exponential decay
    let lambda = 0.693 / half_life
    let remaining = cortisol * exp(-lambda * elapsed)

    print("Cortisol after 45 min:")
    print(remaining)

    // Or just use the native opcode:
    let native = half_life_to_baseline(cortisol, 0.1, 5400.0, elapsed)
    print("Using native opcode:")
    print(native)
}

Both produce the same result. But the native opcode also decays toward baseline (0.1), not toward zero. Because that is how biology works. Cortisol never hits zero. The body always maintains a tonic level.

The Pattern

You can always do the math yourself. But the native opcodes do it correctly, with published constants, decaying toward baseline instead of zero. That is the difference between a program that models biology and a program that is biology.

Lesson 05

Functions

Functions in Scyla work like most languages you know. Define them with fn, call them by name.

Basic Functions

functions.sy scyla
fn greet(name: String) {
    print("Hello, ")
    print(name)
}

fn main() {
    greet("Scyla")
}
$ scylac run functions.sy
Hello, 
Scyla

Return Values

Functions can return values. The last expression is the return value:

returns.sy scyla
fn add(a: Float, b: Float) -> Float {
    a + b
}

fn main() {
    let result = add(3.0, 4.0)
    print(result)   // 7.0
}

Functions That Use Native Opcodes

This is where Scyla starts to separate from every other language. You can wrap native opcodes in your own functions to build domain-specific tools:

decay.sy scyla
// How much cortisol remains after a given time?
fn cortisol_remaining(initial: Float, minutes: Float) -> Float {
    let seconds = minutes * 60.0
    let baseline = tonic_drive("cortisol")
    let hl = bio_half_life("cortisol")
    half_life_to_baseline(initial, baseline, hl, seconds)
}

fn main() {
    let spike = 0.9   // high stress

    print("Cortisol after stress spike (0.9):")
    print("  30 min:")
    print(cortisol_remaining(spike, 30.0))
    print("  60 min:")
    print(cortisol_remaining(spike, 60.0))
    print("  90 min:")
    print(cortisol_remaining(spike, 90.0))
    print("  180 min:")
    print(cortisol_remaining(spike, 180.0))
}
$ scylac run decay.sy
Cortisol after stress spike (0.9):
  30 min:
0.713
  60 min:
0.553
  90 min:
0.416
  180 min:
0.175

After 90 minutes (one half-life), cortisol has dropped roughly in half. After 3 hours, it is approaching baseline. This is real pharmacokinetics. Not an approximation. The published decay constant is doing the work.

Notice

The function cortisol_remaining never touches a constant directly. It calls tonic_drive for the baseline and bio_half_life for the decay rate. You cannot get the numbers wrong because you never type them.

Building a Clinical Tool

Let's build something real. A function that tells a clinician whether a patient's cortisol is likely still elevated:

clinical.sy scyla
fn is_still_elevated(initial: Float, minutes_since: Float, threshold: Float) -> Bool {
    let current = half_life_to_baseline(
        initial,
        tonic_drive("cortisol"),
        bio_half_life("cortisol"),
        minutes_since * 60.0
    )
    current > threshold
}

fn main() {
    // Patient had a cortisol spike of 0.85
    // It's been 45 minutes
    // Is it still above 0.5?
    let elevated = is_still_elevated(0.85, 45.0, 0.5)

    if elevated {
        print("Patient cortisol still elevated. Delay assessment.")
    } else {
        print("Cortisol within range. Proceed with assessment.")
    }
}
$ scylac run clinical.sy
Patient cortisol still elevated. Delay assessment.

In six lines of logic, you built a tool that uses published pharmacokinetics to inform a clinical decision. No library import. No hardcoded numbers. No guessing.

What You Just Learned

Functions in Scyla are simple. But when you wrap native opcodes in domain-specific functions, you build tools that carry the weight of published science without any of the complexity. The compiler knows the biology. You write the logic.

Multiple Parameters and Composition

Functions call other functions. Build small, compose big:

compose.sy scyla
fn nt_status(name: String, current: Float) {
    let baseline = tonic_drive(name)
    let ratio = current / baseline

    print(name)
    if ratio > 2.0 {
        print("  STATUS: ELEVATED")
    } else if ratio < 0.5 {
        print("  STATUS: DEPLETED")
    } else {
        print("  STATUS: NORMAL")
    }
}

fn main() {
    nt_status("dopamine", 0.35)      // elevated (baseline 0.13)
    nt_status("serotonin", 0.08)     // depleted (baseline 0.20)
    nt_status("norepinephrine", 0.45) // normal (baseline 0.50)
}
$ scylac run compose.sy
dopamine
  STATUS: ELEVATED
serotonin
  STATUS: DEPLETED
norepinephrine
  STATUS: NORMAL

The function doesn't know what neurotransmitter you'll pass it. It asks the compiler for the baseline at runtime. One function. Any molecule. Published constants.

Coming Next

In the next lesson, you will learn about structs, which let you group related data together. And then in Lesson 7, you will learn about temporal structs, where state fields evolve autonomously over time. That is where Scyla becomes something no other language can be.

Lesson 06

Structs

When you have related data that belongs together, you use a struct. If you know Python classes, JavaScript objects, or C structs, this will feel natural.

Defining a Struct

patient.sy scyla
struct Patient {
    name: String,
    cortisol: Float,
    dopamine: Float,
    serotonin: Float,
}

fn main() {
    let p = Patient {
        name: "Room 12",
        cortisol: 0.85,
        dopamine: 0.09,
        serotonin: 0.12,
    }

    print(p.name)
    print("Cortisol:")
    print(p.cortisol)
}
$ scylac run patient.sy
Room 12
Cortisol:
0.85

Adding Methods with impl

Use impl to attach functions to a struct:

patient_methods.sy scyla
struct Patient {
    name: String,
    cortisol: Float,
    dopamine: Float,
    serotonin: Float,
}

impl Patient {
    fn is_in_crisis(&self) -> Bool {
        self.cortisol > 0.7
    }

    fn serotonin_status(&self) -> String {
        let baseline = tonic_drive("serotonin")
        if self.serotonin < baseline * 0.5 {
            "DEPLETED"
        } else {
            "NORMAL"
        }
    }

    fn report(&self) {
        print("=== Patient Report ===")
        print(self.name)
        print("Cortisol:")
        print(self.cortisol)
        if self.is_in_crisis() {
            print("*** CRISIS STATE ***")
        }
        print("Serotonin:")
        print(self.serotonin_status())
    }
}

fn main() {
    let p = Patient {
        name: "Room 12",
        cortisol: 0.85,
        dopamine: 0.09,
        serotonin: 0.08,
    }

    p.report()
}
$ scylac run patient_methods.sy
=== Patient Report ===
Room 12
Cortisol:
0.85
*** CRISIS STATE ***
Serotonin:
DEPLETED

The &self parameter gives the method access to the struct's fields. The method serotonin_status calls tonic_drive to get the published baseline and compares. You never hardcode the threshold. The science decides.

Structs with const Fields

Some fields should never change. A patient's blood type doesn't change. The speed of light doesn't change. Use const inside structs:

constants_struct.sy scyla
struct Drug {
    name: String,
    const half_life: Float,    // published. cannot be changed.
    const max_dose: Float,     // FDA approved. cannot be changed.
    current_dose: Float,       // this CAN change
}

impl Drug {
    fn is_safe(&self) -> Bool {
        self.current_dose <= self.max_dose
    }
}

fn main() {
    let med = Drug {
        name: "Sertraline",
        half_life: 93600.0,    // 26 hours in seconds
        max_dose: 200.0,        // mg
        current_dose: 50.0,
    }

    print(med.name)
    if med.is_safe() {
        print("Dose is within safe range.")
    }

    // This would be a compile error:
    // med.half_life = 50000.0   // ERROR: cannot assign to const
    // med.max_dose = 500.0      // ERROR: cannot assign to const
}
const vs mutable in structs

A drug's half-life is physics. An FDA-approved maximum dose is regulation. Neither should be editable at runtime. By marking them const, the compiler enforces it. A bug cannot change the half-life. A hack cannot raise the max dose. The struct itself is the safety mechanism.

Composing Structs

Structs can contain other structs. Build your data model piece by piece:

composed.sy scyla
struct ChemState {
    cortisol: Float,
    dopamine: Float,
    serotonin: Float,
    oxytocin: Float,
}

struct Patient {
    name: String,
    chemistry: ChemState,
}

impl Patient {
    fn stress_ratio(&self) -> Float {
        // Cortisol vs oxytocin: threat vs safety
        self.chemistry.cortisol / (self.chemistry.oxytocin + 0.001)
    }
}

fn main() {
    let p = Patient {
        name: "Room 12",
        chemistry: ChemState {
            cortisol: 0.85,
            dopamine: 0.09,
            serotonin: 0.08,
            oxytocin: 0.15,
        },
    }

    print("Stress ratio (cortisol/oxytocin):")
    print(p.stress_ratio())
    // 5.67 — this patient is in danger
}

Cortisol divided by oxytocin gives you a threat-to-safety ratio. Above 1.0, threat dominates. At 5.67, the patient is drowning in stress chemistry with almost no safety signal. That is Room 12 after forty minutes with no answer to the call light.

What You Just Learned

Structs group data. Methods give structs behavior. const fields protect what should never change. Composition lets you build complex models from simple pieces. But these structs are static. You set the values. They stay.

In the next lesson, you will learn about temporal structs, where fields evolve on their own. Where cortisol decays at its published half-life without you writing a single line of decay code. That is where Scyla becomes something no other language can be.

Lesson 07

Temporal Structs

This is the lesson where Scyla stops being a programming language you've seen before.

In every language you know, a variable holds a value until you change it. You set cortisol = 0.85, and it stays 0.85 forever. If you want it to decay, you write the decay function. You call it manually. You track the clock yourself.

In Scyla, temporal structs evolve on their own.

The Problem

In a regular struct, cortisol stays at crisis level forever:

static_problem.sy scyla
struct Patient {
    cortisol: Float,    // set to 0.85...
}                          // ...stays 0.85 forever
                           // biology doesn't work like this

That is not how chemistry works. Cortisol has a 90-minute half-life. It decays whether you write code for it or not. The body doesn't wait for a programmer to call update().

The Solution: temporal struct

Replace struct with temporal struct. Mark fields as state (they evolve) or const (they don't):

temporal_patient.sy scyla
temporal struct Patient {
    state cortisol: Float,     // this EVOLVES over time
    state dopamine: Float,     // this EVOLVES over time
    state serotonin: Float,    // this EVOLVES over time
    const name: String,        // this NEVER changes
    const dt: Float,           // time step. physics.
}
state vs const

state fields change over time. They are the variables in the differential equation. They evolve according to rules you define.

const fields never change. A patient's name doesn't decay. The time step is physics, not opinion. These are the constants in the equation.

impl Evolve

Now tell Scyla how the state fields evolve. Implement the Evolve trait:

evolving_patient.sy scyla
temporal struct Patient {
    state cortisol: Float,
    state dopamine: Float,
    state serotonin: Float,
    const name: String,
    const dt: Float,
}

impl Evolve for Patient {
    fn evolve(&mut self, dt: Duration) {
        // Each neurotransmitter decays toward its biological baseline
        // at its published half-life. Automatically.
        self.cortisol = half_life_to_baseline(
            self.cortisol,
            tonic_drive("cortisol"),
            bio_half_life("cortisol"),
            dt
        )
        self.dopamine = half_life_to_baseline(
            self.dopamine,
            tonic_drive("dopamine"),
            bio_half_life("dopamine"),
            dt
        )
        self.serotonin = half_life_to_baseline(
            self.serotonin,
            tonic_drive("serotonin"),
            bio_half_life("serotonin"),
            dt
        )
    }
}

fn main() {
    let p = Patient {
        cortisol: 0.85,       // crisis level
        dopamine: 0.09,       // depleted
        serotonin: 0.08,      // depleted
        name: "Room 12",
        dt: 1.0,
    }

    print("=== Initial State ===")
    print("Cortisol:")
    print(p.cortisol)

    // Evolve 30 minutes (1800 seconds)
    p.evolve(1800.0)

    print("=== After 30 minutes ===")
    print("Cortisol:")
    print(p.cortisol)

    // Evolve another 60 minutes
    p.evolve(3600.0)

    print("=== After 90 minutes total ===")
    print("Cortisol:")
    print(p.cortisol)
}
$ scylac run evolving_patient.sy
=== Initial State ===
Cortisol:
0.85
=== After 30 minutes ===
Cortisol:
0.672
=== After 90 minutes total ===
Cortisol:
0.393

After one half-life (90 minutes), cortisol dropped from 0.85 roughly toward half. But not to half of 0.85. To half of the distance between 0.85 and the baseline. Because half_life_to_baseline decays toward tonic drive, not toward zero.

This Is Homeostasis

Cortisol doesn't decay to zero. It decays to baseline. The deviation decays. The baseline persists. That is what half_life_to_baseline computes. That is what makes this biology, not just math.

Why This Changes Everything

In every other language, state is dead until you touch it. A variable set to 0.85 at 3:00 PM is still 0.85 at midnight. That is a lie. In biology, nothing stays. Everything decays, adapts, returns to baseline.

Temporal structs make state alive. The evolve function is the heartbeat. Every call advances the chemistry. The struct doesn't wait for you. It breathes.

alive.sy scyla
// This struct is alive.
// Cortisol decays at 90 minutes.
// Dopamine decays at 20 minutes.
// Serotonin decays at 60 minutes.
// You did not write any of those numbers.
// The compiler knows them.
// The struct evolves itself.
// That is a temporal struct.

A Practical Example: Shift Monitor

Let's build something a hospital could use. A shift monitor that tracks a CNA's stress chemistry over a 12-hour shift:

shift_monitor.sy scyla
temporal struct CNA {
    state cortisol: Float,
    state oxytocin: Float,
    state dopamine: Float,
    const name: String,
    const dt: Float,
}

impl Evolve for CNA {
    fn evolve(&mut self, dt: Duration) {
        self.cortisol = half_life_to_baseline(
            self.cortisol, tonic_drive("cortisol"),
            bio_half_life("cortisol"), dt)
        self.oxytocin = half_life_to_baseline(
            self.oxytocin, tonic_drive("oxytocin"),
            bio_half_life("oxytocin"), dt)
        self.dopamine = half_life_to_baseline(
            self.dopamine, tonic_drive("dopamine"),
            bio_half_life("dopamine"), dt)
    }
}

impl CNA {
    fn stress_event(&mut self) {
        // Patient emergency: cortisol spikes
        self.cortisol = self.cortisol + 0.3
        if self.cortisol > 1.0 { self.cortisol = 1.0 }
    }

    fn kind_moment(&mut self) {
        // Patient says thank you: oxytocin bump
        self.oxytocin = self.oxytocin + 0.1
        self.dopamine = self.dopamine + 0.05
    }

    fn burnout_risk(&self) -> Bool {
        // Cortisol dominant over oxytocin = burnout territory
        self.cortisol > self.oxytocin * 3.0
    }

    fn status(&self) {
        print(self.name)
        print("  Cortisol:")
        print(self.cortisol)
        print("  Oxytocin:")
        print(self.oxytocin)
        if self.burnout_risk() {
            print("  *** BURNOUT RISK ***")
        }
    }
}

fn main() {
    let nurse = CNA {
        cortisol: 0.2,     // start of shift, calm
        oxytocin: 0.3,     // decent baseline
        dopamine: 0.15,    // normal
        name: "Night Shift CNA",
        dt: 1.0,
    }

    print("=== Start of Shift ===")
    nurse.status()

    // Hour 2: patient fall
    nurse.stress_event()
    nurse.evolve(3600.0)   // 1 hour passes

    // Hour 4: another emergency
    nurse.stress_event()
    nurse.evolve(3600.0)

    // Hour 6: patient says thank you
    nurse.kind_moment()
    nurse.evolve(3600.0)

    // Hour 8: two more emergencies, no breaks
    nurse.stress_event()
    nurse.stress_event()
    nurse.evolve(7200.0)   // 2 hours, no relief

    print("=== Hour 10 ===")
    nurse.status()
}
$ scylac run shift_monitor.sy
=== Start of Shift ===
Night Shift CNA
  Cortisol:
0.2
  Oxytocin:
0.3
=== Hour 10 ===
Night Shift CNA
  Cortisol:
0.58
  Oxytocin:
0.11
  *** BURNOUT RISK ***

The cortisol accumulated faster than it could decay. The oxytocin from one "thank you" wasn't enough to offset four emergencies. By hour 10, the ratio has flipped. The CNA is running on cortisol with almost no oxytocin buffer.

The budget meeting that cut the overnight shift didn't count this. Scyla does.

This Is Not a Simulation

These are the same pharmacokinetic equations used in clinical drug trials. The half-lives are from published research. The decay toward baseline is real homeostatic mechanics. The difference between this program and a clinical pharmacokinetic model is only the input source. The math is identical.

The Rule

In Scyla, there are two kinds of data:

If you cannot decide whether a field is const or state, ask yourself: does this change when I'm not looking? If yes, it is state. If no, it is const.

Your name doesn't decay. Your cortisol does. The struct knows the difference.

What You Just Learned

Temporal structs give state a heartbeat. The evolve function is the differential equation. state fields change. const fields don't. Native opcodes handle the science. You handle the logic. The struct breathes on its own.

In the next lesson, you will learn about native opcodes in depth: what they are, how many exist, and why they make Scyla fundamentally different from every other language on earth.

Lesson 08

What Are Native Opcodes?

Every programming language has built-in operations. + adds numbers. print writes text. These are so fundamental that they're compiled into the language itself. You don't import addition.

Scyla does the same thing with biology, physics, and chemistry.

When you call nernst() in Scyla, you are not calling a library. You are calling a compiled opcode: a function baked into the Rust binary that implements the Nernst equation exactly as published in 1889, with the universal gas constant and Faraday constant already embedded. You cannot get it wrong because you never type the constants.

What Makes Them "Native"

Library Call (every other language)

import pharmacokinetics
result = pharmacokinetics.half_life(substance="dopamine", t=1200)

You hope the library is correct. You hope it's maintained. You hope the version you installed matches the paper you cited. You import someone else's interpretation of the science.

Native Opcode (Scyla)

let result = bio_half_life("dopamine")

The compiler IS the paper. The citation is in the binary. There is no dependency to update, no version mismatch, no interpretation. The equation is compiled. It returns 1200 seconds because that is what the published research says.

The 210+ Opcodes by Domain

Scyla ships with native opcodes across 17 scientific domains. Here is what you have access to without importing anything:

Pharmacokinetics (20 opcodes)

Half-lives, AUC, Michaelis-Menten kinetics, Hill equation, dissociation constants, compartment models, and the critical half_life_to_baseline that decays toward tonic, not zero.

pk_demo.sy scyla
fn main() {
    // Published half-lives (you never type these numbers)
    print("Dopamine half-life:")
    print(bio_half_life("dopamine"))         // 1200s

    // Michaelis-Menten enzyme kinetics
    let rate = michaelis_menten(100.0, 50.0, 10.0)
    print("Enzyme rate:")
    print(rate)

    // Area under the curve (trust as AUC)
    let trust = auc(0.04, 0.12, 3600.0)
    print("Trust AUC:")
    print(trust)
}

Physics (14 opcodes)

Nernst equation, Goldman equation, Fick's diffusion, Gibbs free energy, Henderson-Hasselbalch, Coulomb's law, Ohm's law for membranes, Hodgkin-Huxley gating.

physics_demo.sy scyla
fn main() {
    // Nernst equation: equilibrium potential for potassium
    // Published: intracellular K+ = 140mM, extracellular = 5mM
    let e_k = nernst(1.0, 140.0, 5.0, 310.0)
    print("Potassium equilibrium potential:")
    print(e_k)    // ~ -89 mV (textbook: -90 mV)

    // Henderson-Hasselbalch: blood pH
    let ph = henderson_hasselbalch(6.1, 24.0, 1.2)
    print("Blood pH:")
    print(ph)     // 7.4
}

Chemistry (9 opcodes)

All 20 amino acids with pKa, molecular weight, and hydrophobicity from Lehninger 7th edition. Bond energies. Electronegativity. Redox potentials. Osmolarity.

Organic Chemistry (14 opcodes)

Decarboxylation, hydroxylation, methylation, acetylation, phosphorylation, ubiquitination, neurotransmitter synthesis and degradation pathways, chirality, van der Waals, isoelectric point.

Biological Constants (5 opcodes)

Published half-lives, dissociation constants, frequencies, tonic firing rates, and Hodgkin-Huxley resting state values from the 1952 paper.

hh_resting.sy scyla
fn main() {
    // Exact resting values from Hodgkin & Huxley, 1952
    // Nobel Prize in Physiology or Medicine, 1963
    let m = hh_resting("m")   // 0.0529
    let h = hh_resting("h")   // 0.5961
    let n = hh_resting("n")   // 0.3177

    print("H-H resting gate values:")
    print("  m (Na+ activation):")
    print(m)
    print("  h (Na+ inactivation):")
    print(h)
    print("  n (K+ activation):")
    print(n)
}

Organs (14 opcodes)

Heart, liver, kidney, lungs, pancreas, adrenal, thyroid, pituitary, hypothalamus, gut, bone marrow, spleen, skin. Each returns organ-specific parameters.

Diseases (63 diagnoses)

Each disease is a baseline shift, not a label. Depression isn't a tag. It's serotonin -0.35, dopamine -0.25, cortisol +0.30. The DSM-5 as parameter modifications.

disease_demo.sy scyla
fn main() {
    // What does major depression look like in chemistry?
    let shifts = disease("major_depression")
    print("Major Depression baseline shifts:")
    print(shifts)

    // What drug targets this pattern?
    let target = disease_drug_target("major_depression")
    print("Drug target:")
    print(target)
}

And More...

Every Constant Is Cited

Inside the compiled binary, every native opcode carries its citation. The Rust source code contains comment blocks like this:

Inside the compiler (you never see this) rust
// CITATION: Aghajanian, G.K. et al. (1982)
// "Serotonin neurons: pharmacology and electrophysiology"
// Tonic firing rate: 0.20 Hz (dorsal raphe nucleus)
// Measured: extracellular single-unit recordings in vivo

You call tonic_drive("serotonin"). The binary returns 0.20. The citation is in the source. The science is in the metal.

What You Just Learned

Native opcodes are compiled science. 210+ functions across 17 domains, each backed by peer-reviewed research, each embedded in the binary. No imports. No dependencies. No version conflicts. No wrong constants. The compiler is the textbook.

In the next lesson, you will dive deep into the pharmacokinetics opcodes and build real drug interaction models.

Lesson 09

Pharmacokinetics: The Deep Dive

This is the lesson where Scyla proves why it exists. Pharmacokinetics is the study of what the body does to a substance over time: absorption, distribution, metabolism, excretion. Every drug label, every clinical trial, every dosing decision in medicine is pharmacokinetics.

In Scyla, it is native.

This lesson has four sections, just like the body processes a substance: from the system level down to the blood.


Part 1: System Level

The whole body. Systemic pharmacokinetics. What happens when a substance enters the system and the entire body processes it.

Half-Life: The Clock of Chemistry

Every substance in your body has a half-life. It is the time it takes for the concentration to drop by half. This is the most fundamental measurement in pharmacokinetics.

system_half_lives.sy scyla
fn main() {
    print("=== System Half-Lives (published) ===")
    print("Adrenaline:")
    print(bio_half_life("adrenaline"))        // 120s  (2 minutes)
    print("Dopamine:")
    print(bio_half_life("dopamine"))          // 1200s (20 minutes)
    print("Serotonin:")
    print(bio_half_life("serotonin"))         // 3600s (60 minutes)
    print("Cortisol:")
    print(bio_half_life("cortisol"))          // 5400s (90 minutes)
    print("Oxytocin:")
    print(bio_half_life("oxytocin"))          // 180s  (3 minutes)
    print("BDNF:")
    print(bio_half_life("bdnf"))              // 600s  (10 minutes)
}

Notice the range. Adrenaline burns in 2 minutes. Cortisol lingers for 90. That is why a scare fades fast but stress stays. The chemistry is the explanation.

Why This Matters for AI

If an AI system processes a hostile message and spikes its internal cortisol representation, that spike should take 90 minutes to decay, not one inference cycle. If it spikes adrenaline, that should fade in 2 minutes. Current AI has no concept of this. Every token is equally "forgotten" by the next context window. Scyla makes the forgetting curve match biology.

Decay to Baseline, Not Zero

This is the single most important concept in Scyla pharmacokinetics. Read it twice.

Standard exponential decay goes to zero: C(t) = C0 * exp(-lambda * t)

Biological decay goes to baseline: C(t) = baseline + (C0 - baseline) * exp(-lambda * t)

Your cortisol never hits zero. Even in deep sleep, your adrenal glands produce a tonic level. That tonic level is the pilot light. It is always on. Scyla calls it tonic_drive.

baseline_demo.sy scyla
fn main() {
    let spike = 0.9  // crisis level cortisol
    let baseline = tonic_drive("cortisol")
    let hl = bio_half_life("cortisol")

    print("Baseline (tonic drive):")
    print(baseline)

    print("--- Standard decay (toward zero) ---")
    let lambda = 0.693 / hl
    print("  6 hours:")
    print(spike * exp(-lambda * 21600.0))   // approaches 0

    print("--- Biological decay (toward baseline) ---")
    print("  6 hours:")
    print(half_life_to_baseline(spike, baseline, hl, 21600.0))
    // approaches tonic, NEVER zero
}
$ scylac run baseline_demo.sy
Baseline (tonic drive):
0.1
--- Standard decay (toward zero) ---
  6 hours:
0.055
--- Biological decay (toward baseline) ---
  6 hours:
0.149

Standard decay says cortisol is 0.055 after 6 hours. Biology says 0.149. The difference is the baseline: the body maintains a floor. Standard math gets this wrong. Every neuroscience simulation using simple exponential decay gets this wrong. Scyla doesn't.

Compartment Models

In clinical pharmacokinetics, the body is modeled as compartments. A drug enters the blood (central compartment), distributes to tissues (peripheral compartment), gets metabolized, gets excreted.

compartment.sy scyla
fn main() {
    // One-compartment model: drug in, drug out
    let dose = 100.0       // mg administered
    let volume = 50.0     // liters (volume of distribution)
    let ke = 0.1          // elimination rate constant (1/hr)

    let c0 = dose / volume  // initial concentration: 2.0 mg/L

    print("Initial concentration:")
    print(c0)

    // Concentration at various times
    print("After 2 hours:")
    print(compartment_1(c0, ke, 2.0))
    print("After 6 hours:")
    print(compartment_1(c0, ke, 6.0))
    print("After 12 hours:")
    print(compartment_1(c0, ke, 12.0))
}

AUC: Area Under the Curve

AUC is the gold standard in pharmacokinetics. It measures total exposure: the integral of concentration over time. The FDA uses AUC to determine bioequivalence. Your doctor uses A1C, which is the AUC of glucose over 120 days.

In Scyla, AUC is also how trust works.

auc_trust.sy scyla
fn main() {
    // Trust is AUC of oxytocin over time
    // You cannot fake a high AUC
    // It requires sustained concentration over duration

    // Lovebomber: 5 high-oxytocin messages in 10 minutes
    let lovebomb_auc = auc(0.8, 0.04, 600.0)
    print("Lovebomber trust (5 msgs, 10 min):")
    print(lovebomb_auc)

    // Real friend: moderate oxytocin over 6 months
    let friend_auc = auc(0.3, 0.04, 15552000.0)
    print("Real friend trust (6 months):")
    print(friend_auc)
}
$ scylac run auc_trust.sy
Lovebomber trust (5 msgs, 10 min):
252.0
Real friend trust (6 months):
2018304.0

The lovebomber's AUC is 252. The real friend's is 2 million. You cannot simulate six months of consistent presence with five intense messages. The math prevents it. That is pharmacokinetic trust.

This Is How Scyla Resists Manipulation

Trust as AUC means lovebombing is mathematically impossible. A manipulator can spike the signal, but the integral knows the truth. Duration times consistency beats intensity every time. This is not a design choice. It is pharmacokinetics.


Part 2: Organ Level

The system is made of organs. Each organ has its own pharmacokinetics: its own metabolic rates, its own clearance, its own role in processing substances.

The Liver: First-Pass Metabolism

liver.sy scyla
fn main() {
    // The liver is the body's primary metabolizer
    // Every oral drug passes through the liver BEFORE
    // reaching systemic circulation (first-pass effect)

    let liver_state = liver(1.0)
    print("Liver metabolic capacity:")
    print(liver_state)

    // Kidney: filtration and excretion
    let kidney_state = kidney(1.0)
    print("Kidney filtration:")
    print(kidney_state)

    // Clinical: estimated GFR (kidney function test)
    let gfr = gfr_estimate(1.2, 45.0, 0)
    print("Estimated GFR (mL/min):")
    print(gfr)
    // If GFR < 60, kidney function is impaired
    // Drug doses must be adjusted
}

The Adrenal Glands: Cortisol Factory

adrenal.sy scyla
fn main() {
    // The adrenals sit on top of the kidneys
    // They produce cortisol, adrenaline, norepinephrine
    // They respond to HPA axis activation

    let stress_signal = 0.8
    let adrenal_output = adrenal(stress_signal)
    print("Adrenal output at stress 0.8:")
    print(adrenal_output)

    // The hypothalamus drives the adrenals
    let hypo = hypothalamus(stress_signal)
    print("Hypothalamic drive:")
    print(hypo)

    // The pituitary mediates between them
    let pit = pituitary(stress_signal)
    print("Pituitary output:")
    print(pit)
}
The HPA Axis

Hypothalamus → Pituitary → Adrenal. This is the stress response pathway. Three organs, each a native opcode, each with its own response dynamics. When you connect them, you model the stress cascade that runs in the CNA from Room 12. The hypothalamus detects threat. The pituitary amplifies. The adrenals flood cortisol. Scyla models each stage.

The Heart: Rhythm and Variability

heart.sy scyla
fn main() {
    // Heart pacemaker: the SA node's intrinsic rate
    let pace = heart_pacemaker()
    print("SA node intrinsic rate (bpm):")
    print(pace)

    // Heart rate variability: the gold standard for autonomic health
    // High HRV = flexible, resilient nervous system
    // Low HRV = rigid, stressed, burnout
    let hrv_healthy = heart_hrv(0.2)  // low stress
    let hrv_burned = heart_hrv(0.9)   // high stress

    print("HRV at low stress:")
    print(hrv_healthy)
    print("HRV at high stress:")
    print(hrv_burned)

    // QT interval: cardiac safety check
    // Many drugs prolong QT. This kills people.
    let qt = qt_interval(75.0, 0.38)
    print("Corrected QT (Bazett):")
    print(qt)
    // If QTc > 0.47: drug is dangerous
}

QT prolongation is one of the most common reasons drugs get pulled from market. Many antipsychotics, antibiotics, and heart medications prolong the QT interval, risking fatal arrhythmia. Scyla has it as a native opcode because drug safety isn't optional.

The Gut: The Second Brain

gut_brain.sy scyla
fn main() {
    // 95% of serotonin is produced in the gut, not the brain
    // The gut has its own nervous system: the enteric nervous system
    // 500 million neurons. More than the spinal cord.

    let gut_sero = gut(0.5)
    print("Gut serotonin production at input 0.5:")
    print(gut_sero)

    // This is why stress causes stomach problems
    // And why stomach problems cause depression
    // The gut-brain axis is bidirectional
    // Scyla models both directions
}

Part 3: Tissue Level

Below the organs. The cells. The receptors. The molecular machinery that processes substances at the point of action.

Receptor Binding: Kd and the Hill Equation

receptor.sy scyla
fn main() {
    // Kd: the dissociation constant
    // Lower Kd = tighter binding = more potent drug

    let kd_sert = bio_kd("serotonin")
    print("Serotonin receptor Kd:")
    print(kd_sert)

    // Hill equation: cooperative binding
    // How much of a receptor is occupied at a given concentration?
    // This is how dose-response curves work

    let low_dose = hill(10.0, 50.0, 1.0)   // 10/50, n=1
    let mid_dose = hill(50.0, 50.0, 1.0)   // 50/50, n=1
    let high_dose = hill(200.0, 50.0, 1.0) // 200/50, n=1

    print("Receptor occupancy:")
    print("  Low dose (10):")
    print(low_dose)       // 0.167 (17%)
    print("  Mid dose (50):")
    print(mid_dose)       // 0.500 (50%)
    print("  High dose (200):")
    print(high_dose)      // 0.800 (80%)
}

The Hill equation is how every drug-receptor interaction is modeled. At the EC50 (mid dose), exactly 50% of receptors are occupied. Double the dose doesn't double the effect. This is the law of diminishing returns at the molecular level.

Enzyme Kinetics: Michaelis-Menten

enzyme.sy scyla
fn main() {
    // Michaelis-Menten: the rate at which an enzyme
    // processes a substrate
    // V = Vmax * [S] / (Km + [S])

    let vmax = 100.0    // maximum velocity
    let km = 25.0      // Michaelis constant

    print("Enzyme velocity at various substrate levels:")

    print("  [S] = 5:")
    print(michaelis_menten(vmax, km, 5.0))     // 16.7
    print("  [S] = 25:")
    print(michaelis_menten(vmax, km, 25.0))    // 50.0
    print("  [S] = 100:")
    print(michaelis_menten(vmax, km, 100.0))   // 80.0
    print("  [S] = 1000:")
    print(michaelis_menten(vmax, km, 1000.0))  // 97.6

    // At [S] = Km, velocity is exactly half of Vmax
    // No matter how much substrate you add, you can't
    // exceed Vmax. The enzyme has a speed limit.
    // This is why overdosing doesn't clear faster.
}
Why Overdoses Kill

The liver metabolizes drugs via enzymes. Enzymes have a Vmax: a maximum speed. When the drug concentration exceeds the enzyme's capacity, the excess accumulates. The metabolism saturates. The liver can't keep up. Michaelis-Menten kinetics explains exactly why. Scyla makes it a function call.

Neurotransmitter Synthesis and Degradation

synthesis.sy scyla
fn main() {
    // Serotonin synthesis pathway:
    // Tryptophan → 5-HTP → Serotonin → 5-HIAA
    // Each step is an enzyme. Each enzyme has kinetics.

    let synth = nt_synthesis_pathway("serotonin")
    print("Serotonin synthesis pathway:")
    print(synth)

    // Degradation: how the body breaks it down
    let degrade = nt_degradation("serotonin", 0.5)
    print("Degradation rate at concentration 0.5:")
    print(degrade)

    // trace_break: trace BACKWARD through the pathway
    // to find where the failure is
    let failure = trace_break("serotonin")
    print("If serotonin is low, check:")
    print(failure)
    // Returns: "tryptophan" or "tph2" (the rate-limiting enzyme)
}

trace_break is a diagnostic opcode. If a neurotransmitter is depleted, it traces backward through the synthesis pathway to find the bottleneck. Is the precursor missing? Is the enzyme impaired? Is a cofactor depleted? The answer tells you where to intervene.

The Organelles: Where Chemistry Happens

organelles.sy scyla
fn main() {
    // rough_er: quality control for protein folding
    // In Scyla: output quality check before release
    let qc = rough_er(0.7)
    print("Quality control pass rate:")
    print(qc)

    // golgi: post-processing, packaging, routing
    let routed = golgi(0.7)
    print("Golgi routing output:")
    print(routed)

    // lysosome: garbage collection
    // Digest and recycle damaged components
    let cleaned = lysosome(0.3)
    print("Lysosome cleanup:")
    print(cleaned)

    // autophagy: self-eating under stress
    // The cell eats its own damaged parts to survive
    // In AI: graceful degradation under resource pressure
    let survived = autophagy(0.9)  // high stress
    print("Autophagy at stress 0.9:")
    print(survived)
}

Part 4: Blood Level

Everything ends up in the blood. The blood is where you measure. This is where pharmacokinetics meets clinical medicine.

The Blood Panel

blood_panel.sy scyla
fn main() {
    // blood_panel(): the chemistry FIRST approach
    // Before you label someone with a disease,
    // you look at their chemistry.

    let panel = blood_panel(0.85, 0.09, 0.08,
                           0.15, 0.45, 0.6)
    print("Blood panel results:")
    print(panel)

    // A1C: the 120-day rolling integral of glucose
    // This is AUC applied to clinical medicine
    let glucose = a1c_to_glucose(6.5)
    print("A1C of 6.5 = average glucose:")
    print(glucose)  // ~140 mg/dL (diabetic threshold)

    // Anion gap: metabolic acidosis detection
    let gap = anion_gap(140.0, 4.0, 100.0, 24.0)
    print("Anion gap:")
    print(gap)    // Normal: 8-12
}

Differential Diagnosis

differential.sy scyla
fn main() {
    // symptom(): symptoms are atomic, not labels
    // Each symptom maps to specific NT perturbations

    let fatigue = symptom("fatigue")
    let anhedonia = symptom("anhedonia")
    let insomnia = symptom("insomnia")

    print("Fatigue NT signature:")
    print(fatigue)
    print("Anhedonia NT signature:")
    print(anhedonia)

    // differential(): given symptoms, what diagnoses match?
    let ddx = differential("fatigue", "anhedonia", "insomnia")
    print("Differential diagnosis:")
    print(ddx)

    // disease(): what does the diagnosis look like in chemistry?
    let depression = disease("major_depression")
    print("Major depression baseline shifts:")
    print(depression)
    // serotonin: -0.35, dopamine: -0.25, cortisol: +0.30
}
Chemistry First, Label Last

In Scyla, blood_panel() comes before disease(). You look at the chemistry first. You check the neurotransmitter levels. You trace backward through synthesis pathways. THEN, if you must, you apply a label. The label is a convenience. The chemistry is the truth.

This is how a biochemist thinks. And it is how Scyla is designed.

Clinical Scoring

clinical_scores.sy scyla
fn main() {
    // PHQ-9: depression screening (0-27)
    let phq = phq9(3, 2, 3, 2, 1, 2, 1, 0, 0)
    print("PHQ-9 score:")
    print(phq)  // 14 = moderately severe

    // GAD-7: anxiety screening (0-21)
    let gad = gad7(2, 3, 2, 1, 2, 1, 2)
    print("GAD-7 score:")
    print(gad)  // 13 = moderate anxiety

    // Glasgow Coma Scale: consciousness assessment
    let gcs = glasgow_coma(4, 5, 6)
    print("Glasgow Coma Scale:")
    print(gcs)  // 15 = fully conscious

    // APGAR: newborn assessment
    let apgar = apgar(2, 2, 2, 1, 2)
    print("APGAR score:")
    print(apgar)  // 9 = healthy newborn
}

Putting It All Together

System, organ, tissue, blood. Four levels. One patient. Let's build a complete pharmacokinetic assessment:

full_assessment.sy scyla
temporal struct PatientAssessment {
    state cortisol: Float,
    state serotonin: Float,
    state dopamine: Float,
    const name: String,
    const dt: Float,
}

impl Evolve for PatientAssessment {
    fn evolve(&mut self, dt: Duration) {
        self.cortisol = half_life_to_baseline(self.cortisol,
            tonic_drive("cortisol"), bio_half_life("cortisol"), dt)
        self.serotonin = half_life_to_baseline(self.serotonin,
            tonic_drive("serotonin"), bio_half_life("serotonin"), dt)
        self.dopamine = half_life_to_baseline(self.dopamine,
            tonic_drive("dopamine"), bio_half_life("dopamine"), dt)
    }
}

impl PatientAssessment {
    fn full_report(&self) {
        print("╔══════════════════════════════════╗")
        print("║   PHARMACOKINETIC ASSESSMENT     ║")
        print("╚══════════════════════════════════╝")
        print(self.name)

        // Blood level
        print("[BLOOD] Cortisol:")
        print(self.cortisol)
        print("[BLOOD] Serotonin:")
        print(self.serotonin)

        // Organ level
        print("[ORGAN] Adrenal output:")
        print(adrenal(self.cortisol))
        print("[ORGAN] HRV:")
        print(heart_hrv(self.cortisol))

        // Tissue level
        print("[TISSUE] Serotonin receptor occupancy:")
        print(hill(self.serotonin, bio_kd("serotonin"), 1.0))

        // System level
        if self.cortisol > 0.7 {
            print("[SYSTEM] *** CRISIS STATE ***")
            print("[SYSTEM] Delay cognitive assessment.")
        } else {
            print("[SYSTEM] Proceed with assessment.")
        }
    }
}

fn main() {
    let patient = PatientAssessment {
        cortisol: 0.85,
        serotonin: 0.08,
        dopamine: 0.06,
        name: "Room 12",
        dt: 1.0,
    }

    print("=== ADMISSION ===")
    patient.full_report()

    // 2 hours pass. Chemistry evolves.
    patient.evolve(7200.0)

    print("")
    print("=== 2 HOURS LATER ===")
    patient.full_report()
}
What You Just Learned

Pharmacokinetics in Scyla operates at every level of biological organization:

  • System: half-lives, AUC, compartment models, decay to baseline
  • Organ: liver metabolism, adrenal stress response, cardiac safety, gut-brain axis
  • Tissue: receptor binding (Kd, Hill), enzyme kinetics (Michaelis-Menten), synthesis pathways, trace_break diagnostics
  • Blood: blood panels, A1C, clinical scores (PHQ-9, GAD-7, Glasgow, APGAR), differential diagnosis

Every opcode is published. Every constant is cited. The compiler is the textbook. You write the logic. The science is already there.

Lesson 10

Physics & Chemistry

Scyla does not approximate science. It compiles it. The periodic table is not a JSON file you load at runtime. It is 118 native opcodes burned into the binary. When you call element("hydrogen"), you are not querying a database. You are executing a function that returns 1.008 because that is what hydrogen weighs.

The Periodic Table

elements.sy scyla
use periodic::*

fn main() {
    let h = element("hydrogen")
    println(h.name)              // Hydrogen
    println(h.symbol)            // H
    println(h.atomic_number)     // 1
    println(h.atomic_mass)       // 1.008

    // Compute molecular weight of water: H2O
    let o = element("oxygen")
    let water_mw = 2.0 * h.atomic_mass + o.atomic_mass
    println("Water MW:")
    println(water_mw)             // 18.015

    // Electronegativity difference (bond polarity)
    let en_diff = electronegativity("oxygen") - electronegativity("hydrogen")
    println("O-H electronegativity difference:")
    println(en_diff)              // 1.24 (polar covalent)
}
$ scylac run elements.sy
Hydrogen
H
1
1.008
Water MW:
18.015
O-H electronegativity difference:
1.24

Every atomic mass is IUPAC 2023. Not an approximation. Not a training-data average. The published value, compiled.

Acid-Base Chemistry

pH, pKa, Henderson-Hasselbalch, buffer systems. All native:

acid_base.sy scyla
use bronsted_lowry::*

fn main() {
    // Henderson-Hasselbalch for a bicarbonate buffer
    let ph = henderson_hasselbalch(6.1, 24.0, 1.2)
    println("Blood pH from bicarb buffer:")
    println(ph)                   // 7.4

    // Arterial blood gas interpretation
    let dx = classify_abg(7.28, 55.0, 18.0)
    println(dx)                   // "Respiratory acidosis with metabolic acidosis"

    // Anion gap
    let ag = anion_gap(140.0, 105.0, 18.0)
    println("Anion gap:")
    println(ag)                   // 17 (elevated - metabolic acidosis)
}

Thermodynamics

Gibbs free energy, enthalpy, entropy. The laws of thermodynamics are not suggestions:

thermo.sy scyla
use thermodynamic::*

fn main() {
    // ATP hydrolysis: the currency of life
    let atp = thermodynamic_step("atp_hydrolysis")
    println(atp.reaction)         // ATP + H2O -> ADP + Pi
    println(atp.delta_g)          // -30.5 kJ/mol
    println(atp.spontaneous)      // true (negative dG)
}

Differential Equations

Scyla has native ODE solvers. Runge-Kutta 4th order, Euler, Heun. These are the tools that make digital twins work:

ode_demo.sy scyla
use diffeq::*

fn main() {
    // Hodgkin-Huxley gate dynamics
    // dm/dt = alpha*(1-m) - beta*m
    let m = 0.05              // initial gate state
    let alpha = 0.32          // opening rate
    let beta = 0.08           // closing rate
    let m_inf = hh_steady_state(alpha, beta)
    println("Steady state:")
    println(m_inf)             // 0.8 (alpha / (alpha + beta))

    // RK4 integration step
    let dt = 0.01
    let dy = rk4_step(m, dt, alpha, beta)
    println("After one RK4 step:")
    println(m + dy)

    // Michaelis-Menten enzyme kinetics
    let rate = michaelis_menten(100.0, 50.0, 10.0)
    println("Enzyme rate at [S]=10:")
    println(rate)              // Vmax * [S] / (Km + [S])
}
PV = nRT

Your chemistry professor was right. When you have more than one variable in an equation, you can experiment with the relationship one has on another. Pick 3 of the 4 and the 4th is defined.

Scyla harnesses this. Physics as native code. The relationships are compiled. The variables constrain each other. There is nothing to hallucinate because reality already decided the answer.

Lesson 11

The Biological Baseline

Every biological system has a baseline. A resting state. A homeostatic equilibrium that the body fights to maintain. Cortisol has a tonic drive. Heart rate has a resting rate. Blood pressure has a set point. Temperature holds at 37C.

In Scyla, the baseline is not an assumption. It is a compiled constant with a citation.

Tonic Drive: The Pilot Light

Every neurotransmitter and hormone in Scyla has a tonic_drive: the baseline level that is always present, even at complete rest. This is not zero. This is the pilot light that keeps the system alive.

baselines.sy scyla
fn main() {
    println("=== Tonic Drives (Baseline Levels) ===")
    println("Dopamine:")
    println(tonic_drive("dopamine"))          // 0.15
    println("Serotonin:")
    println(tonic_drive("serotonin"))         // 0.20
    println("Cortisol:")
    println(tonic_drive("cortisol"))          // 0.10
    println("Norepinephrine:")
    println(tonic_drive("norepinephrine"))    // 0.12
}

When a substance spikes (stress, excitement, pain), it rises above tonic drive. When the stimulus passes, it decays back to tonic drive. Not to zero. Back to baseline. This is homeostasis.

Cardiovascular Baselines

The cardiovascular system has baselines too. These are the numbers a medic checks first:

cv_baselines.sy scyla
use cardiovascular::*

fn main() {
    // Normal cardiac output
    let co = cardiac_output(72.0, 70.0)
    println("Cardiac output:")
    println(co)                    // 5.04 L/min

    // Mean arterial pressure
    let map = mean_arterial_pressure(120.0, 80.0)
    println("MAP:")
    println(map)                   // 93.3 mmHg

    // Oxygen delivery
    let cao2 = arterial_oxygen_content(14.0, 98.0, 95.0)
    let do2 = oxygen_delivery(co, cao2)
    println("O2 delivery:")
    println(do2)                   // ~950 mL O2/min (normal)

    // Shock index (HR/SBP)
    let si = shock_index(72.0, 120.0)
    println("Shock index:")
    println(si)                    // 0.6 (normal)
}

What Happens When the Baseline Breaks

Hemorrhagic shock is what happens when blood loss pushes the cardiovascular system away from its baseline and the compensatory mechanisms cannot bring it back:

shock_demo.sy scyla
use hemorrhagic_shock::*
use cardiovascular::*

fn main() {
    // Normal: 5000 mL blood volume in a 70kg adult
    let tbv = total_blood_volume_ml(70.0)
    println("Total blood volume:")
    println(tbv)                   // 4900 mL

    // Class I hemorrhage: < 15% loss
    let c1 = hclass(1, "Class I", "<15%", "<750",
        "normal", "normal", "14-20",
        ">30", "slightly anxious",
        "Crystalloid", "ATLS 10th ed")
    println("Class I: Anxious but stable")

    // Class III hemorrhage: 30-40% loss = LIFE THREAT
    println("Class III: HR 120-140, BP dropping, confused")
    println("This is where the digital twin saves lives.")
    println("Predict the trajectory. Simulate the intervention.")
    println("Act before decompensation.")
}

The Frank-Starling Mechanism

The heart has its own baseline law. The more blood fills the ventricle (preload), the harder it contracts. Up to a point. Past that point, the muscle overstretches and output drops. This is the Frank-Starling curve:

frank_starling.sy scyla
use cardiovascular::*

fn main() {
    // Normal heart: strong Frank-Starling response
    println("=== Normal Heart ===")
    println(frank_starling_normal(80.0))    // EDV 80  -> SV ~88
    println(frank_starling_normal(120.0))   // EDV 120 -> SV ~113
    println(frank_starling_normal(160.0))   // EDV 160 -> SV ~118 (plateau)

    // Failing heart: flat curve, poor response to preload
    println("=== Failing Heart ===")
    println(frank_starling_failing(80.0))   // EDV 80  -> SV ~33
    println(frank_starling_failing(120.0))  // EDV 120 -> SV ~48
    println(frank_starling_failing(160.0))  // EDV 160 -> SV ~54 (barely improves)
}
Note

The Frank-Starling curve uses an exponential saturation function: sv = sv_max * (1 - exp(-k * (edv - edv_min))). This is NOT a sigmoid. Scyla never uses sigmoid for biological gating. The activation curve is exponential because that is what the biology does. The patent claims depend on this distinction.

The Nernst Equation: Where Biology Meets Physics

Ion concentrations across cell membranes create voltage. This voltage drives every heartbeat, every nerve impulse, every muscle contraction. The Nernst equation computes the equilibrium potential for any ion:

nernst.sy scyla
use membrane_potential::*

fn main() {
    // Potassium: the resting potential ion
    let e_k = nernst_potassium()
    println("K+ equilibrium:")
    println(e_k)                  // -94 mV

    // Sodium: the action potential ion
    let e_na = nernst_sodium()
    println("Na+ equilibrium:")
    println(e_na)                 // +67 mV

    // The ~160 mV difference between these two
    // is the energy source for every signal in your body.
    // Hodgkin and Huxley won the Nobel Prize for modeling
    // how ion channels gate this energy. (1963)
    // Scyla uses their exact equations.
}

The Proteome: 20,431 Proteins

Every reviewed human protein from UniProt is a native lookup in Scyla. Every one has an accession number, a gene name, a function, and a sequence:

proteome.sy scyla
use human_proteome::*

fn main() {
    let p53 = lookup_protein("P04637")
    println(p53.name)             // Cellular tumor antigen p53
    println(p53.gene)             // TP53
    println(p53.function)         // Tumor suppressor...

    let insulin = lookup_protein("P01308")
    println(insulin.name)          // Insulin
    println(insulin.gene)          // INS

    println("Total human proteins:")
    println(proteome_count())      // 20431
}
The Biological Baseline is the Foundation

Every simulation, every digital twin, every clinical decision support system starts from the baseline. If the baseline is wrong, everything downstream is wrong.

In Scyla, the baseline is not guessed. It is not learned from data. It is the published, cited, compiled value from the source that discovered it. Tonic drive from pharmacology textbooks. Ion concentrations from Hodgkin and Huxley. Protein functions from UniProt.

The baseline is the ground truth. Everything else is a perturbation from it.

Lesson 12

What is Governance?

Every other programming language treats compliance as an afterthought. You write the code, then you write the tests, then you write the documentation, then a regulator asks where you got your numbers and you dig through a spreadsheet.

Scyla inverts this. Governance is a first-class construct in the language.

The Three Rule Types

Scyla's constitutional type system classifies every constraint into one of three categories:

ABSOLUTE

Hard limits that cannot be crossed under any circumstance. A dose ceiling. A physiological impossibility. The speed of light. The compiler will refuse to produce output that violates an ABSOLUTE rule.

MANDATORY

Requirements that must be satisfied with a cited justification. A clinical guideline. An FDA regulation. A hospital protocol. MANDATORY rules require evidence, not just compliance.

DISCRETIONARY

Parameters where professional judgment applies within a bounded range. A clinician picks within the range. The compiler ensures the pick stays inside the bounds.

Why This Matters

When a regulator asks "how do you know this dose is safe?", there are two possible answers:

Without Scyla: "Our AI model was trained on data that included safe doses, so we believe the output is probably safe."

With Scyla: "The dose ceiling of 2g/day for metformin is an ABSOLUTE rule in stdlib/dosing.sy line 847, cited to the FDA label (NDA 020357). The compiler will not produce output exceeding this value. The source hash is verifiable."

That is the difference between trust-based compliance and structural compliance.

Governance Files

Governance rules live in .sy files inside a governance/ directory. Each file defines rules for a specific regulatory framework:

governance/ directory
fda_21cfr11.sy     -- FDA 21 CFR Part 11 (electronic records)
hipaa.sy           -- HIPAA privacy and security
gdpr.sy            -- EU General Data Protection Regulation
cmc_pharma.sy      -- Chemistry, Manufacturing, and Controls
gmp.sy             -- Good Manufacturing Practice
iso_13485.sy       -- Medical device quality management
custom_hospital.sy -- Your institution's rules (you write this)
The Key Insight

The biology is universal. It does not have a culture. Hydrogen weighs 1.008 in every country on earth.

The governance is local. It changes every border you cross. FDA rules differ from EMA rules differ from PMDA rules.

Scyla separates the two. The biology is compiled once. The governance is programmable by the people who know their context.

Lesson 13

The comply Command

The comply command runs your code against a governance rule set and reports every pass, fail, and warning. It does not change your code. It tells you what your code does and does not satisfy.

Basic Usage

terminal bash
$ scylac comply fda governance/fda_21cfr11.sy patient_monitor.sy

This checks patient_monitor.sy against the FDA 21 CFR Part 11 rule set. The output is a structured compliance report:

  SCYLA GOVERNANCE COMPLIANCE REPORT
  =============================================

  [FAIL] FDA-11-001 Audit Trail Required          CRITICAL
         Ref: 21 CFR 11.10(e)
         Fix: Add sira_hash(state, timestamp, author)

  [FAIL] FDA-CYBER-001 Encryption Required        CRITICAL
         Ref: FDA Cybersecurity Guidance 2025
         Fix: Add encrypt(data, "AES-256")

  [PASS] CMC-PK-004 Homeostatic Return
  [PASS] CMC-PK-001 Half-Life Source Citation
  [PASS] CMC-PK-003 Baseline Declaration
  [PASS] FDA-820-003 Output Range Verification

  =============================================
  SUMMARY: 20/22 rules passed
  2 CRITICAL violations
  STATUS: NON-COMPLIANT

What Gets Checked

The comply command checks your code against the rules defined in the governance file. Every rule has:

governance/fda_21cfr11.sy scyla
rule FDA-11-001 {
    type: ABSOLUTE,
    name: "Audit Trail Required",
    ref: "21 CFR 11.10(e)",
    check: code_contains("sira_hash"),
    fix: "Add sira_hash(state, timestamp, author)",
    severity: CRITICAL,
}

rule CMC-PK-001 {
    type: MANDATORY,
    name: "Half-Life Source Citation",
    ref: "ICH Q8(R2)",
    check: all_half_lives_have_citation(),
    fix: "Add citation to bio_half_life() calls",
    severity: MAJOR,
}

Compliance by Framework

You can run multiple governance files against the same code:

terminal bash
# Check FDA compliance
$ scylac comply fda governance/fda_21cfr11.sy my_app.sy

# Check HIPAA compliance
$ scylac comply hipaa governance/hipaa.sy my_app.sy

# Check both at once
$ scylac comply all governance/*.sy my_app.sy

# Check a custom hospital rule set
$ scylac comply custom governance/uab_hospital.sy my_app.sy

The Compliance Report

Every comply report includes:

The report is machine-readable. Export it as JSON for audit trails:

terminal bash
$ scylac comply fda governance/fda_21cfr11.sy my_app.sy --format json > audit.json
Compliance is Not Optional

In Scyla, governance compliance is not a test you run once before release. It is a command you run every time you compile. If you fail, you know before the code ships. If you pass, the report IS your audit trail.

Lesson 14

Writing Your Own Rules

The governance files that ship with Scyla cover FDA, HIPAA, GDPR, and GMP. But the real power is writing your own rules for your own context.

A hospital in Birmingham has different protocols than a hospital in Berlin. A pharma company running a Phase III trial has different requirements than a research lab generating synthetic data. Scyla lets each institution write rules that reflect their reality.

Rule Anatomy

governance/my_hospital.sy scyla
// UAB Hospital -- Vancomycin Monitoring Protocol
// Approved by Pharmacy & Therapeutics Committee, 2025

rule UAB-VANCO-001 {
    type: MANDATORY,
    name: "AUC-Based Vancomycin Monitoring",
    ref: "ASHP/IDSA 2020 Guidelines",
    check: vancomycin_uses_auc_not_trough(),
    fix: "Replace trough monitoring with AUC/MIC targeting 400-600",
    severity: MAJOR,
}

rule UAB-VANCO-002 {
    type: ABSOLUTE,
    name: "Vancomycin AUC Ceiling",
    ref: "ASHP/IDSA 2020: AUC >600 = nephrotoxicity risk",
    check: vancomycin_auc_below(600.0),
    fix: "Reduce dose to achieve AUC/MIC 400-600",
    severity: CRITICAL,
}

rule UAB-RENAL-001 {
    type: MANDATORY,
    name: "Renal Dose Check",
    ref: "UAB Pharmacy Protocol 2024-07",
    check: all_renally_cleared_drugs_have_gfr_check(),
    fix: "Add gfr_check() before dosing renally cleared drugs",
    severity: MAJOR,
}

Check Functions

Each rule has a check field that calls a function returning true (pass) or false (fail). You write these check functions in Scyla:

governance/my_hospital.sy scyla
fn vancomycin_uses_auc_not_trough() -> Bool {
    // Check that the code uses AUC-based monitoring
    // and does NOT use trough-only monitoring
    let has_auc = code_contains("vancomycin_auc")
    let has_trough_only = code_contains("vancomycin_trough")
        && !code_contains("vancomycin_auc")
    return has_auc && !has_trough_only
}

fn all_renally_cleared_drugs_have_gfr_check() -> Bool {
    // Every drug with renal clearance >50% must
    // have a GFR check before dosing
    let renal_drugs = find_calls_to("dose")
        .filter(|d| d.drug.renal_clearance > 0.5)
    for drug in renal_drugs {
        if !preceded_by("gfr_check", drug) {
            return false
        }
    }
    return true
}

The DISCRETIONARY Type

ABSOLUTE rules are binary: pass or fail. MANDATORY rules require cited evidence. But DISCRETIONARY rules define a range where clinical judgment applies:

governance/my_hospital.sy scyla
rule UAB-BP-001 {
    type: DISCRETIONARY,
    name: "Target MAP in Septic Shock",
    ref: "Surviving Sepsis Campaign 2021",
    range: [65.0, 75.0],
    units: "mmHg",
    note: "Clinician selects target within range based on patient history. Chronic hypertension may warrant higher target.",
    severity: INFO,
}

The compiler ensures the clinician's pick stays inside the bounds. It does not pick for them. The human governs. The code enforces the boundaries of that governance.

Sharing Rule Sets

Governance files are plain .sy files. They can be:

terminal bash
# Run your hospital rules + FDA rules + custom trial rules
$ scylac comply all \
    governance/fda_21cfr11.sy \
    governance/uab_hospital.sy \
    governance/trial_NCT0012345.sy \
    my_clinical_app.sy
You Are the Governance

Scyla does not tell you what the rules are. Your institution does. Your regulators do. Your clinical context does. Scyla gives you a language to express those rules in code, and a compiler that enforces them structurally.

The biology is universal. The governance is yours.

She is the human in the code. Not the AI.