A deterministic markup language for the AI era.
FACET is a markup language for authoring, managing, and executing instructions for AI systems. It merges the clarity of plain text with the rigor of code to build reproducible AI pipelines.
Every FACET document compiles to a single canonical JSON — no YAML-style ambiguity, no hidden magic. Version v1.1 turns FACET into a compile-time configuration language with modularity, logic, static typing, and a pure transformation pipeline (lenses).
+------------------+ +------------------+ +-----------------+
| | | | | |
| .facet file | --> | FACET Parser | --> | Canonical JSON |
| (Source Text) | | (Lenses, | | (Output) |
| | | Contracts) | | |
+------------------+ +------------------+ +-----------------+
| | |
|-- Facets (@user) |-- Data transforms |-- Deterministic
|-- Attributes (name="") |-- Schema validation |-- Reproducible
|-- Lenses (|> trim) |-- Type checking |-- Tool‑ready
|-- Contracts (@output) |-- Error handling |-- Always valid
At authoring time you write readable .facet files. The reference parser expands imports, resolves variables, applies conditionals, validates types/contracts, and executes pure lens pipelines — producing a single canonical JSON that downstream tools can rely on.
Modern AI stacks drown in a mix of ad-hoc prompts, brittle scripts, and ambiguous configs. FACET replaces that with contracts and determinism.
- Deterministic by design: One source → one canonical JSON. No surprises.
- Contract-first prompting: Use
@outputto enforce JSON Schema on model responses. Prompts stop being strings and become APIs with guarantees. - Compile-time intelligence:
@import,@vars,@var_types, andif="EXPR"give вам модульность, параметризацию и статическую проверку ещё до запуска. - Pure transformation pipeline: Lenses (
|>) — встроенные детерминированные функции (в т.ч.choose(seed)/shuffle(seed)), без I/O и сайд-эффектов. - Security model: Import allowlists, sandboxed lenses, отсутствие неявного доступа к окружению.
FACET doesn’t just configure AI — it programs the instruction itself.
| Capability / Tooling | YAML + JSON | Jsonnet/Cue | Templating (Jinja/Mustache) | FACET |
|---|---|---|---|---|
| Canonical, deterministic serialization | ✅ | ❌ (runtime text) | ✅ | |
| Contract-first (enforce model output) | 🟡 External glue | 🟡 | ❌ | ✅ @output |
| Compile-time imports & deterministic merge | 🟡 Plugins | 🟡 | ❌ | ✅ @import |
| Static typing for variables | 🟡 Schema hacks | ✅ | ❌ | ✅ @var_types |
| Conditional inclusion (no runtime eval) | 🟡 | ✅ | ✅ if="EXPR" |
|
| Pure pipelines for text/JSON transforms | ❌ | 🟡 | ❌ | ✅ Lenses |
| Deterministic randomness (seeded) | ❌ | 🟡 | ❌ | ✅ choose/shuffle |
| Sandbox for user plugins | 🟡 | ❌ | ✅ (spec §12) |
FACET combines the readability of config with the guarantees of a DSL that’s purpose-built for AI orchestration.
- Facets & Contracts: Structured blocks (
@system,@user,@plan,@output, …). - Modularity:
@importwith deterministicmerge/replace. - Variables:
@varsand string interpolation{{path}}; scalar substitution$name. - Static Typing:
@var_typesenforcestype/enum/min/max/patternat compile time. - Conditionals:
if="EXPR"on any facet or list item (no runtime eval). - Lenses:
value |> lensA |> lensB(...)— pure, safe transformations (incl. deterministicchoose(seed)/shuffle(seed)). - Security: allowlisted imports, sandboxed lenses, no implicit env reads.
# 1) Reuse prompt fragments and contracts
@import "common/prompts.facet"
@import(path="common/output_contracts.facet", strategy="merge")
# 2) Declare and type-check variables at compile-time
@vars
username: "Alex"
mode: "expert"
seed: 42
features: ["recursion", "tail-calls"]
greetings: ["Hi", "Hello", "Hey"]
@var_types
mode: { type: "string", enum: ["user", "expert"] }
seed: { type: "int", min: 0 }
# 3) Conditional facets
@system(role="Deep Technical Expert", if="mode == 'expert'")
constraints:
- "Use precise terminology."
# 4) Interpolation + deterministic choice + formatting
@user
request: """
{{ greetings |> choose(seed=$seed) }}, {{username}}!
Explain recursion with examples.
""" |> dedent
# 5) Conditional list items
@plan
steps:
- "Introduction"
- "Tail-call optimization" (if="'tail-calls' in features")
# 6) Contract-first output (enforced by host)
@output
schema:
type: "object"
required: ["summary","examples"]
properties:
summary: { type: "string" }
examples: { type: "array", items: { type: "string" } }
✅ Readable • ✅ Dynamic • ✅ Reproducible • ✅ Contract-enforced
- Imports → 2) Variable resolution → 3)
@var_typesvalidation → - Conditional filtering → 5) Anchors/Aliases → 6) Lenses →
- Canonical JSON construction (stable key order)
Compile-time facets (
@import,@vars,@var_types) do not appear in the final JSON.
{
"system": {
"_attrs": { "role": "Deep Technical Expert" },
"constraints": ["Use precise terminology."]
},
"user": {
"request": "Hello, Alex!\nExplain recursion with examples."
},
"plan": {
"steps": ["Introduction", "Tail-call optimization"]
},
"output": {
"schema": {
"type": "object",
"required": ["summary","examples"],
"properties": {
"summary": { "type": "string" },
"examples": { "type": "array", "items": { "type": "string" } }
}
}
}
}(The exact content depends on chosen seed and inputs; structure and ordering are deterministic.)
Requirements: Python ≥ 3.9
pip install facet-lang- Create a file:
cat > my_prompt.facet << EOF @vars mode: "user" @system(if="mode == 'expert'") role: "You are a world-class computer science professor." @user request: "Explain recursion to me." EOF
- Run in "user" mode (no system block):
facet canon --var "mode=user" my_prompt.facet - Run in "expert" mode (system appears):
facet canon --var "mode=expert" my_prompt.facet
Python API
from facet_lang import canonize
doc = """@user
request: "Hello"
"""
print(canonize(doc, resolve_mode="all"))CLI
# Canonize a file
facet canon --resolve=all samples/complex.facet
# From stdin
cat samples/complex.facet | facet canon -FACET_SYSTEM_PROMPT.md helps LLMs produce valid .facet files by following syntax and canonization rules.
Use it as a system message in your agent/tooling to generate FACET natively.
- Imports: allowlisted roots, no network URLs, no path escapes.
- Variables: no implicit env reads — host must pass them explicitly.
- Conditionals: dedicated parser (no
eval). - Lenses: sandboxed, timeouts, no I/O/time/random; deterministic
choose/shufflerequire explicitseed.
- Enterprise prompts with SLAs: enforce output contracts → stable downstream pipelines.
- Multi-env orchestration: one source with
if="EXPR"/@vars→ dev/staging/prod without file sprawl. - Agent pipelines: shared libraries via
@import, deterministic transforms via lenses. - AB-tests & seeded variants: reproducible
choose(seed)/shuffle(seed)for prompt alternatives.
“Why a dedicated language? Why not YAML + JSONSchema?” YAML remains ambiguous and typically requires external glue/scripts. FACET provides a single deterministic pipeline end‑to‑end: imports → typing → conditionals → lenses → canonical JSON.
“Why not Cue/Jsonnet?”
They are general‑purpose. FACET is purpose‑built for AI: @output contracts, built‑in lenses, explicit conditional semantics, bans on I/O/randomness, and determinism out of the box.
“How do we keep it secure?” The spec includes sandboxing and restrictions (see §12). Lenses are pure (no I/O), imports are allowlisted, and variables are only provided explicitly by the host.
- Finalize spec, strengthen reference parser, expand samples & docs.
- LSP (VS Code/JetBrains/Zed/NeoVim): realtime diagnostics, autocomplete, hovers.
- SDKs: TypeScript / Rust (наряду с Python).
- CI/CD: ready-made GitHub Actions for canonization & schema checks.
- FACET MCP Server: high-performance agent-first runtime.
- Plugin Registry: curated, sandboxed lens ecosystem.
- Playground: visual canonization & learning.
- Discussions: ideas, proposals, showcases
- Issues: bugs & tasks
- PRs: features, fixes, docs
Emil Rokossovskiy — @rokoss21
MIT — see LICENSE
