A TypeScript superset where the LLM writes the implementation and the human supervises.
Cheese is a general-purpose programming language for vibe coding. Humans own the intent: types, signatures, requirements, and executable acceptance contracts. An LLM produces the implementation. Cheese makes that division of responsibility part of the language and its tooling instead of leaving it as a prompting convention.
Project status: Cheese is an early v0 prototype. The first end-to-end example works, but the language and generated layout are still evolving. It is not ready for production use.
Most TypeScript is already valid Cheese. The language adds declaration-level
constructs such as imagine, requirements, and ensure:
/// greeting.chz.ts
export imagine function greetLikePirate(name: string): string {
requirements(`
Greet the person like a friendly pirate.
The greeting must start with "Ahoy, ".
`);
ensure(
greetLikePirate("Cheese") === "Ahoy, Cheese!",
"The name must appear in the greeting.",
);
ensure("Every greeting follows the public contract.", () => {
const greeting = greetLikePirate("Ren");
assert(greeting.startsWith("Ahoy, "));
assert(greeting.includes("Ren"));
});
}There is deliberately no implementation body for the human to fill in:
imaginemarks a symbol that an LLM must implement.requirementsdescribes intent and constraints in natural language.ensure(condition, message?)records a concrete executable contract.ensure(message, () => { ... })records a multi-step synchronous or asynchronous scenario.
The contracts are emitted as deterministic *.ensure.ts tests. They do not
depend on model-authored tests to choose inputs or invoke the symbol.
Run chz realize during development:
chz realize greeting.chz.tsCheese then:
- extracts the human-authored symbol specifications and contracts;
- builds a symbol-level dependency graph;
- asks a configured Realizer to implement each symbol in dependency order;
- runs type checks and tests independently of the Realizer's own completion claim; and
- writes auditable TypeScript, tests, and cache metadata under
chz/realization/.
Human-written code is preserved alongside the generated implementation. Code
that can load before realized symbols is emitted as __prologue__.ts; code
that uses realized symbols is emitted as __epilogue__.ts.
chz/realization/greeting/
├── realization-cache.json
├── implementation.ts
├── implementations/
│ ├── __prologue__.ts
│ ├── greetLikePirate.ts
│ └── __epilogue__.ts
└── tests/
├── test_greetLikePirate.ensure.ts
└── test_greetLikePirate.autogen.ts
Realized artifacts are meant to be reviewed and committed. Builds and CI use
ordinary committed TypeScript and do not call an LLM. The long-term module
design uses a generated sidecar file next to each .chz.ts source, allowing
existing tools such as tsc, esbuild, Vite, Metro, and webpack to consume the
result without a Cheese-specific build step or plugin.
The repository currently runs directly from TypeScript source. Install the development dependencies and check the project:
npm install
npm test
npm run typecheck
npm run chz -- --helpWithout a chz.config.js, the built-in OpenAI-compatible Realizer reads:
export OPENAI_MODEL="<model>"
export OPENAI_API_KEY="<api-key>"
# Optional for another OpenAI-compatible endpoint:
export OPENAI_BASE_URL="https://example.com/v1"
npm run chz -- realize path/to/example.chz.tsYou can inspect parsing or prompts without starting a model-backed realization:
npm run chz -- realize path/to/example.chz.ts --json
npm run chz -- realize path/to/example.chz.ts --dry-runFor project-wide runs, configure Realizers and source globs:
/// chz.config.js
import { ChzOpenAIRealizer, defineConfig } from "chz";
export default defineConfig({
include: ["src/**/*.chz.ts"],
jobs: 4,
realizers: [
new ChzOpenAIRealizer({
model: process.env.OPENAI_MODEL,
apiKey: process.env.OPENAI_API_KEY,
baseURL: process.env.OPENAI_BASE_URL,
}),
],
});Then omit the file argument:
npm run chz -- realizeThe first configured Realizer that supports a symbol type is selected.
chz.config.js can also set limits for turns, retries, cycle size, and the
active profile.
Cheese is designed around a durable ownership boundary:
| Human-owned | LLM-owned |
|---|---|
| Intent and requirements | Implementations |
| Public types and signatures | Implementation-focused typedefs |
| Executable acceptance contracts | Additional unit tests |
| Review and approval | Explicitly documented assumptions |
The Realizer operates through a fixed tool surface rather than an unrestricted
shell. Filesystem boundaries, read-before-write checks, turn limits, output
limits, and independent verification are enforced by the harness. When the
specification leaves a meaningful product decision open, the Realizer can ask
the human; answers are recorded in CONTEXTS.md and become part of subsequent
realization context and cache invalidation.
Standing project rules go in CHZPROJECT.md, the Cheese counterpart of a
CLAUDE.md — a symlink to one works. Each session picks up the nearest such
file at or above its source directory and quotes it into the prompt inside a
tag whose closing sequence is defused, so file content cannot impersonate the
sections the engine writes around it. It is guidance only: it cannot lift a
harness boundary or widen the active profile. Editing it does not invalidate
symbols that are already realized.
Generated code is optimized for auditability as well as correctness. Ambiguous
decisions must be marked with ASSUMPTION: comments so reviewers can find the
places where the implementation interpreted underspecified intent.
The current graph engine realizes dependencies before their dependents and
groups manageable cycles into a single session. Independent graph groups can
run concurrently with chz realize -j N.
Successful symbols are recorded in realization-cache.json. On later runs:
- unchanged green symbols are reused;
- public-surface changes invalidate dependents;
- internal-only changes rerun dependent tests without immediately calling an LLM;
- edited or drifted artifacts fall back to realization; and
- changes to human layers or
CONTEXTS.mdtrigger the corresponding safety checks.
When nothing changed but the result is simply not good enough, chz realize --reroll asks for another attempt at the same contract; --reroll=<a,b>
limits it to named symbols. It suppresses cache reuse and nothing else, so
dependents fall under the unchanged-surface rule above and only re-run their
tests. The previous artifact is overwritten — realized code is committed, so
git already holds it.
The implemented v0 focuses on:
imagine functionandimagine class;- natural-language
requirements; - executable
ensurecontracts; - OpenAI-compatible and custom Realizers;
- a constrained agentic harness with independent verification;
- per-symbol dependency ordering, bounded cycles, caching, and parallel jobs; and
- prologue/implementation/epilogue emission.
The broader design also covers usage-created contracts, required members,
generative imagine resource assets, capability-oriented @profile
declarations, sidecar module shims, chz verify, override preservation, and a
cross-file dependency graph. These areas are planned or only partially
implemented in the current prototype.
- Introduction and language tour
- Module resolution and the no-build principle
- Realization output and overrides
- Realizer architecture
- Symbol dependency graph
- Harness rules and tool specification
- Canonical harness prompt
- Design sketches and discussion history
The numbered specifications are living design documents. Korean specifications are currently canonical; when code and documentation disagree, the documentation is more likely to reflect the latest design decision.
See examples/ for the collision-detection milestone, small
self-contained cases, symbol dependencies, and cross-file design examples.