Idea
The idea behind the experiments
Why an analyzable language?
To find out how a program computed a result, whether a handler can read another user's data, or where the same logic is repeated, you usually read all of its code or trust a description of it. When an agent wrote the program, that description is the agent's own summary. We split the program in two: reusable engines handle execution and integrations, and code written in Bosatsu, a typed functional language, supplies the calculations, handlers, and policies. Our tools then read the compiled Bosatsu to explain results, map dependencies, and check permissions.
What we want to find out is whether reading the program this way helps us build useful applications, find mistakes, and choose structures that make the next change easier.
Use existing libraries through a deliberate interface
A server needs HTTP, authentication, storage, and deployment machinery. Implementing all of that in a young language would mean rebuilding much of an ecosystem. An engine written in a conventional language can use that language’s libraries and expose the operations an application needs.
In Yichus’s service examples, the engine is written in JavaScript: it accepts requests and interprets database effects. Bosatsu defines routes, typed handlers, and access policies. That side is code: a handler can decide whether a caller may edit a post while the engine supplies the storage operation.
This reduces the amount of infrastructure that needs a Bosatsu implementation. It still takes work to build adapters and expose new capabilities. The engine’s interface determines what an application can express and what the tools can inspect.
Bosatsu’s compiler gives Yichus checked types, expressions, and source locations. Explicit operations identify where the program requests effects such as a database write. That structure lets the tools follow dependencies and operations without guessing their meaning from function names. The technical overview follows these facts from compilation to the diagrams and checks.
See the service engine boundary or explore the running service examples.
Familiar tools already benefit from explicit structure
Type checking is an established example. A checker uses types to reject operations that do not fit their inputs, such as calling a value that is not a function. The TypeScript handbook illustrates this before execution. A successful check answers a particular question; it does not establish that an application implements the intended policy.
Bazel’s Starlark language shows another useful division. Build rules describe dependencies and register actions; Bazel later executes those actions using compilers and other tools. The rule implementation describes the work without implementing the compiler it invokes. This gives the build engine an explicit structure to operate on.
Yichus explores that principle for application behavior. Bosatsu supplies the language and type checker. Yichus uses the compiled program to expose dependencies, explain results, and check additional declared properties. Like a type check, each answers its own question and does not establish that the application implements the intended policy.
Inspect the organization before adding code
When adding an endpoint, a person or agent needs to know where its behavior belongs. Which handlers already do something similar? Which validation and access rules do they share? Would another copy make a later policy change harder?
A structural view can put those relationships in one place. Compare neighboring implementations, follow their shared definitions, and inspect the code that matters to the change. After editing, compare the same part of the program again and rerun the relevant checks.
Sometimes a new requirement also helps choose an abstraction. The Forum exercise compares a helper that returns a complete response with one that returns fields a caller can extend. Adding a preview operation makes the consequences of those interfaces visible.
Checks depend on what the engine promises
Bosatsu has no exceptions, no unbounded loops, and no side effects outside its explicit operations, so an analyzer has fewer cases to handle, but the exposed operations still need precise meaning. If a check assumes an atomic transaction, the storage adapter must provide that behavior. If it reasons about the caller, the runtime must supply the correct authenticated identity. Hiding arbitrary behavior behind an external call leaves the analysis with less it can establish.
Application authors can declare expectations as well as types: an access policy, a law, a model of state changes, or a required structure for related handlers. The checks give three kinds of evidence. Static facts come from reading the compiled program without running it: access checks inspect its key and guard rules, and what they report holds for every input under the stated assumptions. Exploring a declared finite domain means running the compiled transaction handlers through every case of a domain the author declares, including retries; a run that exhausts its budget is inconclusive. Generated test cases drive law and conformance checks, so a pass covers only the cases that ran. A conformance check takes the author’s declared model of how state should change, runs the handlers on generated operations, and compares the resulting state with the model after each step; it does not prove the host engine correct for every execution.
Judge the idea on a change you want to make
Yichus is an experimental project; whether the extra tools help is a question to test. The evaluation record includes methods, raw results, and unsuccessful comparisons.
Start with a calculator, inspect the Forum’s extension choices, or build and check an API with an agent.