AI News HubLIVE
站内改写

An AI opinionated ideal language that ignores human-friendliness

Pact is a programming language designed for AI agents, emphasizing machine-readable specifications and constraints over human-friendliness. It's based on S-expressions and features provenance, effect tracking, totality, latency budgets, and dependency graphs. The compiler generates Rust code and includes tools for web scaffolding and YAML spec conversion. While strong for service contracts, it has limitations for algorithmic specifications.

Article intelligence

EngineersAdvanced

Key points

  • Pact is an S-expression language for AI agents, prioritizing metadata and formal specifications.
  • Key features include provenance, effect tracking, totality, and latency budgets.
  • It compiles to Rust and offers web scaffolding and YAML-to-Pact conversion.
  • Suitable for API service contracts but not for algorithms or data structures.

Why it matters

This matters because pact is an S-expression language for AI agents, prioritizing metadata and formal specifications.

Technical impact

May affect model selection, inference cost, product capability, and evaluation benchmarks.

Notifications You must be signed in to change notification settings

Fork 3

Star 45

BranchesTags

Open more actions menu

Folders and files

NameName

Last commit message

Last commit date

Latest commit

History

8 Commits

8 Commits

doc

doc

examples

examples

src

src

.gitignore

.gitignore

Cargo.lock

Cargo.lock

Cargo.toml

Cargo.toml

README.md

README.md

grammar.ebnf

grammar.ebnf

Repository files navigation

A compiler for Pact — a programming language designed for AI agents, not humans.

Pact inverts the usual ratio: programs are mostly specification, provenance, and constraints with a thin layer of computation. The logic is the easy part. Knowing why something exists, what else is affected, and what guarantees must hold is where the language spends its budget.

What is Pact?

Pact is an S-expression based language where every function carries rich, machine-readable metadata:

(fn get-user-by-id :provenance {req: "SPEC-2024-0042#section-3", test: ["T-101" "T-102" "T-103"]} :effects [db-read http-respond] :total true :latency-budget 50ms :called-by [api-router/handle-request admin-panel/user-detail]

(param id UUID :source http-path-param :validated-at boundary)

(returns (union (ok User :http 200 :serialize :json) (err :not-found {:id id} :http 404) (err :invalid-id {:id id} :http 400)))

(let [validated-id (validate-uuid id)] (match validated-id (err _) (err :invalid-id {:id id}) (ok uuid) (match (query user-store {:id uuid}) (none) (err :not-found {:id uuid}) (some u) (ok u)))))

Key language features:

Provenance — every function and type knows why it exists (spec reference, author, tests)

Effect tracking — functions declare exactly what I/O they perform (reads, writes, sends)

Totality — functions marked :total true must handle all cases exhaustively

Latency budgets — performance constraints are part of the code, not tribal knowledge

Dependency graphs — :called-by makes impact analysis instant

Union return types — every possible outcome is enumerated with HTTP status mappings

Type invariants — constraints like :min-len, :max-len, :format are first-class

Building

cargo build --release

No external dependencies. Just Rust's standard library.

Usage

Generate a .pct file from a YAML spec (human intent → machine format)

pact generate examples/user-service.spec.yaml -o user-service.pct

Compile a Pact file to Rust source code

pact compile examples/user-service.pct -o output/

Compile targeting pact-runtime (produces code that compiles against pact-runtime crate)

pact compile --runtime examples/user-service.pct -o output/

Scaffold an Axum web project from a Pact file

pact scaffold examples/user-service.pct -o ../user-service-web/

Check for errors without generating code

pact check examples/user-service.pct

Parse only (show the concrete syntax tree)

pact parse examples/minimal.pct

Codegen backends

The compiler ships two codegen backends:

Backend Flag Output Use case

v1 (rust.rs) (default) Standalone Rust with trait-based effects Inspection, documentation

v2 (rust_v2.rs) --runtime Rust targeting pact-runtime crate Compilable, runnable applications

The --runtime backend produces Rust that compiles against pact-runtime and can be used directly in applications like pact-web. It handles:

use pact_runtime::prelude::*; imports

#[derive(Serialize, Deserialize)] on structs

Named input structs for map-typed parameters (e.g., CreateUserInput)

Named fields in error enum variants (not inline structs)

Store trait bounds instead of per-store effect traits

Builtin mapping (query → store.query_by_id(), insert! → store.insert(), etc.)

HasId, HasUniqueFields, from_input(), validate_input() implementations

Web Project Scaffolding

The scaffold command generates a complete Axum web project from a .pct file — routes, handlers, HTML templates, and Cargo.toml. This is a one-time generation intended as a starting point that you customize afterward.

1. Scaffold the web project

pact scaffold examples/user-service.pct -o ../user-service-web/

2. Generate the domain code into it

pact compile --runtime examples/user-service.pct -o ../user-service-web/src/generated/

3. Build and run

cd ../user-service-web && cargo run

This produces:

user-service-web/ ├── Cargo.toml # Dependencies (axum, tokio, serde, pact-runtime) └── src/ ├── main.rs # AppState, Router with HTML + JSON API routes ├── handlers.rs # HTML handlers (list, show, create, delete) + JSON API handlers ├── html.rs # Tailwind CSS HTML helpers (page, nav, table, form, alert) └── generated/ └── mod.rs # "pub mod user_service;"

Route inference

Routes are inferred from the AST — no configuration needed:

AST signal Generated route

EffectKind::Reads/Writes on a store GET /{plural} (list), GET /{plural}/new (form), POST /{plural}/{id}/delete

FnDef with UUID :source http-path-param + reads-only GET /{plural}/{id} (show) + GET /api/{plural}/{id}

FnDef with Map :source http-body + writes POST /{plural} (create) + POST /api/{plural}

FieldDef :format :email in forms

FieldDef :min-len, :max-len minlength/maxlength attributes

Variant :http 404 StatusCode::NOT_FOUND in match arms

Generated handler patterns

The generated handlers follow the same patterns as the hand-written pact-web:

List — store.list_all() → HTML table with Tailwind styling

Show — calls domain function → matches Ok/Err variants with correct HTTP status codes

Create (HTML) — Form → calls domain function → redirect on success, error alert on failure

Create (API) — Json → calls domain function → JSON response with status

Delete — store.delete(&uuid) → redirect to list

Spec-to-Pct Generator

The generate command translates human-readable YAML specs (Layer 0 — human intent) into .pct files (Layer 1 — AI-native format) that feed into the compiler pipeline:

Spec (.yaml) → YamlParser → SpecAST → PctEmitter → .pct file → [compiler]

YAML Spec Format

Write requirements in plain English:

spec: SPEC-2024-0042 title: "User service" owner: platform-team domain: User: fields:

  • name: required, string, 1-200 chars
  • email: required, email format, unique
  • id: auto-generated, immutable

endpoints: get-user: description: "Returns a user by ID" input: user id (from URL) outputs:

  • success: the user found (200)
  • not found: when the ID doesn't exist (404)

constraints:

  • max response time: 50ms
  • read-only

create-user: description: "Creates a new user" input: user data (from body) outputs:

  • created: the new user (201)
  • duplicate email: email already exists (409)
  • validation failed: invalid input (422)

constraints:

  • idempotent by: email
  • max response time: 200ms

quality:

  • all functions must be total

traceability: known dependencies: api-router, admin-panel

What Gets Mapped

Spec descriptor Generated .pct

required, string, 1-200 chars (field name String :min-len 1 :max-len 200) + invariant

email format, unique (field email String :format :email :unique-within )

auto-generated, immutable (field id UUID :immutable :generated)

read-only constraint effect set db-read [:reads ]

max response time: 50ms :latency-budget 50ms

idempotent by: email :idempotency-key (hash (. input email))

output success (200) (ok Type :http 200 :serialize :json)

output not found (404) (err :not-found {:id id} :http 404)

all functions must be total :total true on every function

The generator also scaffolds function bodies: read endpoints get validate-query-match logic, write endpoints get validate-insert-match logic.

The generated .pct is validated by round-tripping through lexer, parser, and lowerer before writing to disk.

Scope and Limitations

The generator is designed for service contract specifications — CRUD endpoints, API contracts, input validation, error variants. It handles the domain well:

Domain types with field constraints

Read/write endpoints with HTTP status mappings

Effect tracking, latency budgets, idempotency keys

Traceability and provenance metadata

It is not designed for algorithmic specifications (data structures, sorting algorithms, state machines). Those require language features Pact doesn't yet have: generic types, recursive types, trait bounds, and algorithmic body templates.

Compiler Pipeline

The compiler has 6 phases:

Source (.pct) → Lexer → Parser (CST) → Lowering (AST) → Semantic Analysis → Codegen (Rust)

Phase What it does

Lexer Tokenizes source into symbols, keywords, strings, integers, durations, regex literals

Parser Builds a generic S-expression tree (lists, vectors, maps, atoms) — no semantic knowledge

Lowering Converts CST to typed AST (Module, TypeDef, FnDef, Expr, Pattern, etc.)

Semantic analysis Name resolution, effect checking, match exhaustiveness

Codegen Emits Rust source: structs, traits, enums, functions with doc comments

What Gets Generated

v1 backend (default)

Given a Pact module, the compiler produces Rust code with:

Pact construct Rust output

(type User ...) pub struct User with validate() method

(effect-set db-read ...) pub trait DbRead with typed methods

(fn get-user ...) pub fn get_user() with trait-bounded context

(returns (union ...)) pub enum GetUserResult with http_status() and Display

:provenance, :called-by, etc. Doc comments preserving all metadata

:invariants, :min-len, :max-len Validation logic in validate()

v2 backend (--runtime)

The runtime-targeting backend produces code that compiles and runs:

Pact construct Rust output

(type User ...) pub struct User with HasId, HasUniqueFields, validate(), validate_input(), from_input()

(param input {:name String}) pub struct CreateUserInput (named struct)

(effect-set db-read ...) Store trait bound on function

(fn get-user ...) pub fn get_user(store: &impl Store, ...)

(err :not-found {:id id}) NotFound { id: String } (named fields)

(query store {:id uuid}) store.query_by_id(&uuid)

(insert! store (build User input)) store.insert(User::from_input(input.clone()))

(validate-against User input) User::validate_input(&input)

(non-empty? errors) non_empty(&errors)

Examples

The examples/ directory contains several Pact modules:

minimal.pct — Starting point

The smallest valid module. One type, one effect set, one function.

pact compile examples/minimal.pct -o output/

user-service.pct — Canonical example

The reference example from the language spec. A user CRUD service with two functions (get-user-by-id, create-user), full provenance, effect tracking, and union return types.

pact compile examples/user-service.pct -o output/

auth-service.pct — Authentication

Token-based authentication with session management. Demonstrates multiple effect sets (session reads/writes, user lookup, audit logging), expiration handling, and password verification flows.

pact compile examples/auth-service.pct -o output/

inventory.pct — Inventory management

Stock tracking with reservations. Multiple types (Product, StockEntry, Reservation), cross-type queries, quantity constraints, and write-heavy operations.

pact compile examples/inventory.pct -o output/

notification.pct — Notifications

Multi-channel delivery with template rendering. Shows send effects (email-gateway, sms-gateway), long latency budgets (2000ms), and chained operations (render → deliver → persist).

pact compile examples/notification.pct -o output/

Language Reference

Module

Every .pct file contains a single module:

(module module-name :provenance {req: "SPEC-ID", author: "agent:name", created: "ISO-8601"} :version 7 :parent-version 6 :delta (operation target "description")

;; declarations: types, effect-sets, functions ...)

Types

Types have named fields with constraints:

(type User :invariants [(> (strlen name) 0) (matches email #/.+@.+/)] (field id UUID :immutable :generated) (field name String :min-len 1 :max-len 200) (field email String :format :email :unique-within user-store))

Supported field annotations: :immutable, :generated, :min-len, :max-len, :format, :unique-withi

[truncated for AI cost control]