Adds 'event_suffix: "Payload"' as a top-of-file directive. When set,
the .proto generator appends the suffix to every 'event' block's
emitted message name. Default (no directive) preserves the existing
'event CreateGroup' → 'message CreateGroup' behavior.
Why: federated-meetup's handwritten proto names every transition
payload CreateGroupPayload, AddStewardPayload, etc. (the convention
that the wrapper message carries a 'Payload' suffix and the event
type lives in 'oneof payload { ... }'). Without this directive, the
Speckl-generated proto would emit 'message CreateGroup' and the
consumer Go code would fail to find the types it imports.
The test fixture uses three tests:
- directive parsed and stored on SpeckNode
- directive absent → eventSuffix undefined
- both quoted ("Payload") and bare (Payload) values accepted
The reset of (parseSpeck as any)._protoPackage / _goPackage /
_eventSuffix at the start of parseSpeck fixes a pre-existing
static-field-hack leak where a previous test's metadata would
persist into the next test's parse. Documented as a known
anti-pattern in spec-compiler-dogfood SKILL.md; full cleanup
to a local-object pattern is tracked separately. The minimum
fix here is 'reset at start of parse' which restores test
isolation without refactoring the entire metadata-collection
path.
End-to-end verified: running generateProtobuf against a speck
with event_suffix: "Payload" emits 'message CreateGroupPayload'
and 'message AddStewardPayload' (correct).
All 52 tests pass. tsc build clean.
Reference: .hermes/skills/spec-compiler-dogfood/references/
speckl-federated-meetup-protobuf-migration.md — the migration
unblocks when every generated message name matches what the
consumer's Go imports expect.
|
||
|---|---|---|
| .forgejo/workflows | ||
| compiler | ||
| demo | ||
| docs | ||
| examples | ||
| landing | ||
| out | ||
| reference-agent | ||
| scripts | ||
| speckdl | ||
| .gitignore | ||
| bench-rust.mjs | ||
| bench-rust.sh | ||
| fix-z3-again.py | ||
| LICENSE | ||
| README.md | ||
| typescript | ||
Speckl
A judgement transport utility for AI-generated specifications. Fulfills NIST SA-11 (human-in-the-loop for automated outputs).
Speckl is a specification language (SpeckDL) with a compiler that produces runnable software — TypeScript and provenance artifacts (PROV-O, CycloneDX, SPDX) — from a single source of truth. Write what your system should do. Prove it. Ship it.
The Core Insight
AI generates code at machine speed. Humans own specifications. SpeckDL is the shared space where both can work.
- Human-judgeable — SpeckDL is declarative enough that a person can inspect a spec and say "yes, this captures my intent." The compiled output is opaque; the spec is not.
- AI-writable — SpeckDL's constrained grammar and declarative semantics are tractable for LLMs to produce and reason about. Agents draft. Humans review. Both operate on the same semantic layer.
- Compiled, not generated — The SpeckDL compiler is deterministic. No LLMs in the compilation path. Same spec, same output — always.
What Speckl Does Now
Speckl is a working compiler that turns formal specifications into multiple target representations:
.speckdl spec ──→ TypeScript ← typed, importable classes
├── PROV-O (RDF) ← W3C provenance standard
├── CycloneDX SBOM ← OWASP software bill of materials
└── SPDX SBOM ← Linux Foundation SBOM standard
State Machine Compilation (inspired by TLA+)
spec ToggleSwitch {
state: Status = Off
enum Status = On | Off
init: {
Status = Off
}
action FlipSwitch {
require: true
if Status == On {
Status = Off
} else {
Status = On
}
}
}
This compiles to a runnable TypeScript class with verified state transitions + guards.
Provenance Embedded at Compile Time
Every compilation embeds a complete provenance record — PROV-O RDF traces the spec → code derivation, CycloneDX and SPDX SBOMs capture the software supply chain. When an auditor asks "where did this behavior come from?", you query the graph, not Jira.
Real-World Examples
The compiler has been validated against:
| Example | Source | Status |
|---|---|---|
| ToggleSwitch | SpeckDL tutorial | ✅ All artifacts |
| AccountLedger | Banking ledger with debit/credit | ✅ All artifacts |
| TwoPhaseCommit | TLA+ port | ✅ All artifacts |
| Paxos | TLA+ port | ✅ All artifacts |
| Raft | TLA+ port | ✅ All artifacts |
| TigerBeetleLedger | Naive TigerBeetle core | ✅ All artifacts (3 TS type errors in progress) |
Getting Started
git clone https://os.scoble.me/forgejo/sscoble/speckl
cd speckl/compiler
npm install
# Compile an example
node dist/index.js ../examples/ToggleSwitch.speck -o out/switch
ls out/switch/
# ToggleSwitch.ts ToggleSwitch.prov-o.jsonld
# ToggleSwitch.cyclonedx.json ToggleSwitch.spdx.json
Key Documents
- Whitepaper v2 — Complete: 8 sections, ~19,000 words. Covers the spec-code gap, SpeckDL language, compiler architecture, embedded provenance, consensus protocols, compliance applications, related work, and roadmap.
- Speckl by Example — Guided tutorial from ToggleSwitch through Raft, with TLA+ comparison table.
- Distribution Strategy — Prioritized roadmap: Show HN → arXiv → blog → consulting pipeline. Conference landscape for 2026-2027.
- Strategy Ladder — Open standard → Consulting → Developer Tool/SaaS → Compliance API.
- SpeckDL Spec — Language definition v0.2.
- State Machine Extension —
state/init/actionkeywords, Set/Map/List types.
Strategy Ladder
| Phase | Focus | Status |
|---|---|---|
| A — Open Standard | SpeckDL language, compiler, whitepaper, examples | ✅ Complete (compiler working, whitepaper done) |
| B — Consulting | Hands-on engagements with regulated-industry teams | 📋 One-pager drafted, awaiting review |
| C — Developer Tool/SaaS | Self-serve spec validation, provenance browser | 🔮 Future |
| D — Compliance API | Enterprise audit reports, traceability matrices | 🔮 Future |
Validation Status
- Compiler: 41/41 tests passing (TypeScript codegen)
- TypeScript: Type-safe compilation from specs
- TLA+ Trilogy: TwoPhaseCommit, Paxos, Raft all compile
- Compiler Self-Spec:
speckl-compile.speckdldefines the Speckl compiler in SpeckDL — generates all artifacts (known TypeScript errors tracked in engineering#9)
Known Issues
The rewriteExpr function in the TypeScript generator applies spurious this.state. prefixes to function parameters in guard expressions. Tracked in marcus/engineering#9. Parser also drops precondition:/postcondition: blocks on some action bodies.
Contributing
Speckl is open source under the MIT license. Contributions welcome:
- Language design — refine SpeckDL syntax and semantics
- Compiler development — TypeScript/Node.js, help fix open issues
- Formal methods — verify the compilation pipeline, add TLA+ examples
- Compliance expertise — validate regulatory models (NIST, IEC 62304, DO-178C)
- Documentation — tutorials, guides, case studies
Open an issue or submit a pull request.
License
MIT © Scott Scoble / Greybeard Holdings, LLC