Build your own HAPPI runtime.
One stdin loop. Seven event types. Any provider. Working starters in Python, TypeScript, Go, Rust, and Bash — copy, paste, run.
The minimal contract
A HAPPI runtime reads JSON envelopes from stdin, dispatches to a provider, and writes NDJSON event lines to stdout. That is the entire interface.
Envelope (stdin) — required fields
"v": "happi/1.0"
Protocol version — always this string
"id": "<string>"
Request ID — echoed on every event
"cmd": "<string>"
Provider command, e.g. anthropic.messages.create
"args": [...]
Positional args — first element is usually the prompt
Seven event types (stdout) — emit these in order
A minimal synchronous runtime needs only started, delta,
completed, and error. The remaining three enable
tool-calling and agent recursion.
{"v":"happi/1.2","id":"req-1","type":"started","ts":0}
{"v":"happi/1.2","id":"req-1","type":"delta","ts":12,"text":"Hello"}
{"v":"happi/1.2","id":"req-1","type":"delta","ts":24,"text":", world"}
{"v":"happi/1.2","id":"req-1","type":"completed","ts":180,"usage":{"input_tokens":3,"output_tokens":2}}
Python runtime starter
pip install anthropicEnv: export your Anthropic key as
ANTHROPIC_KEYRun:
echo '{"v":"happi/1.0","id":"1","cmd":"anthropic.messages.create","args":["Hello"]}' | python3 happi_runtime.py
#!/usr/bin/env python3
"""Minimal HAPPI/1.2 runtime in Python.
Reads JSON envelopes from stdin, emits NDJSON events to stdout.
Set your provider key in the environment before running.
"""
import json
import os
import sys
import anthropic
def emit(req_id: str, **fields) -> None:
sys.stdout.write(json.dumps({"v": "happi/1.0", "id": req_id, **fields}) + "\n")
sys.stdout.flush()
def dispatch(envelope: dict) -> None:
req_id = envelope["id"]
cmd = envelope.get("cmd", "")
args = envelope.get("args", [])
prompt = args[0] if args else ""
emit(req_id, type="started", ts=0)
try:
if cmd.startswith("anthropic."):
client = anthropic.Anthropic(api_key=os.environ["ANTHROPIC_KEY"])
ts = 0
with client.messages.stream(
model="claude-opus-4-7",
max_tokens=1024,
messages=[{"role": "user", "content": prompt}],
) as stream:
for text in stream.text_stream:
ts += 1
emit(req_id, type="delta", ts=ts, text=text)
usage = stream.get_final_message().usage
emit(req_id, type="completed", ts=ts + 1,
usage={"input_tokens": usage.input_tokens,
"output_tokens": usage.output_tokens})
else:
raise ValueError(f"Unknown cmd: {cmd!r}")
except Exception as exc:
emit(req_id, type="error", ts=0,
code="dispatch_error", message=str(exc))
if __name__ == "__main__":
for raw in sys.stdin:
raw = raw.strip()
if raw:
dispatch(json.loads(raw))
TypeScript runtime starter
npm install @anthropic-ai/sdk ts-node typescriptEnv: export your Anthropic key as
ANTHROPIC_KEYRun:
echo '{"v":"happi/1.0","id":"1","cmd":"anthropic.messages.create","args":["Hello"]}' | ts-node happi_runtime.ts
#!/usr/bin/env ts-node
/**
* Minimal HAPPI/1.2 runtime in TypeScript/Node.js.
*
* Reads JSON envelopes from stdin, emits NDJSON events to stdout.
* Set your provider key in the environment before running.
*/
import { createInterface } from 'readline'
import Anthropic from '@anthropic-ai/sdk'
const rl = createInterface({ input: process.stdin, terminal: false })
const client = new Anthropic({ apiKey: process.env.ANTHROPIC_KEY })
function emit(id: string, fields: Record<string, unknown>): void {
process.stdout.write(JSON.stringify({ v: 'happi/1.0', id, ...fields }) + '\n')
}
rl.on('line', async (line: string) => {
if (!line.trim()) return
const envelope = JSON.parse(line)
const { id, cmd, args = [] } = envelope
const prompt: string = (args as string[])[0] ?? ''
emit(id, { type: 'started', ts: 0 })
try {
if (cmd.startsWith('anthropic.')) {
let ts = 0
const stream = client.messages.stream({
model: 'claude-opus-4-7',
max_tokens: 1024,
messages: [{ role: 'user', content: prompt }],
})
for await (const event of stream) {
if (
event.type === 'content_block_delta' &&
event.delta.type === 'text_delta'
) {
emit(id, { type: 'delta', ts: ++ts, text: event.delta.text })
}
}
const msg = await stream.getFinalMessage()
emit(id, { type: 'completed', ts: ++ts, usage: msg.usage })
} else {
throw new Error(`Unknown cmd: ${cmd}`)
}
} catch (err: unknown) {
emit(id, {
type: 'error', ts: 0,
code: 'dispatch_error', message: String(err),
})
}
})
Go runtime starter
github.com/anthropics/anthropic-sdk-go inside dispatch()
for a real provider call.Run:
go run happi_runtime.go
// Minimal HAPPI/1.2 runtime in Go — standard library only.
// Wire a real provider SDK inside dispatch() for live inference.
package main
import (
"bufio"
"encoding/json"
"fmt"
"os"
"time"
)
// Envelope is the HAPPI request shape — one JSON object per stdin line.
type Envelope struct {
V string `json:"v"`
ID string `json:"id"`
Cmd string `json:"cmd"`
Args []any `json:"args,omitempty"`
}
// emit writes a single HAPPI event line to stdout.
func emit(id, evType string, extra map[string]any) {
ev := map[string]any{
"v": "happi/1.0",
"id": id,
"type": evType,
"ts": time.Now().UnixMilli(),
}
for k, v := range extra {
ev[k] = v
}
b, _ := json.Marshal(ev)
fmt.Println(string(b))
}
// dispatch handles one envelope and emits the event stream.
func dispatch(env Envelope) {
emit(env.ID, "started", nil)
switch {
case env.Cmd == "echo":
// Built-in echo — no provider needed; useful for smoke-testing.
arg := ""
if len(env.Args) > 0 {
if s, ok := env.Args[0].(string); ok {
arg = s
}
}
emit(env.ID, "delta", map[string]any{"text": arg})
emit(env.ID, "completed", map[string]any{
"usage": map[string]int{"input_tokens": 0, "output_tokens": 0},
})
default:
emit(env.ID, "error", map[string]any{
"code": "unknown_cmd",
"message": "cmd not implemented: " + env.Cmd,
})
}
}
func main() {
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
var env Envelope
if err := json.Unmarshal(scanner.Bytes(), &env); err != nil {
continue // skip malformed lines
}
dispatch(env)
}
}
Rust runtime starter
serde = { version = "1", features = ["derive"] },
serde_json = "1"Run:
cargo run
// Minimal HAPPI/1.2 runtime in Rust.
// Cargo.toml [dependencies]:
// serde = { version = "1", features = ["derive"] }
// serde_json = "1"
//
// Add reqwest or an Anthropic SDK crate for live provider calls.
use serde::Deserialize;
use serde_json::{json, Value};
use std::io::{self, BufRead, Write};
/// The HAPPI envelope read from stdin (one JSON object per line).
#[derive(Deserialize)]
struct Envelope {
#[allow(dead_code)]
v: String,
id: String,
cmd: String,
#[serde(default)]
args: Vec<Value>,
}
/// Write a single HAPPI event line to stdout.
fn emit(id: &str, fields: Value) {
let mut ev = json!({ "v": "happi/1.0", "id": id });
if let (Some(obj), Some(extra)) = (ev.as_object_mut(), fields.as_object()) {
for (k, v) in extra {
obj.insert(k.clone(), v.clone());
}
}
println!("{}", ev);
io::stdout().flush().ok();
}
/// Handle one envelope and emit the event stream.
fn dispatch(env: &Envelope) {
emit(&env.id, json!({ "type": "started", "ts": 0 }));
match env.cmd.as_str() {
"echo" => {
// Built-in echo — useful for smoke-testing without a provider.
let text = env.args.first().and_then(Value::as_str).unwrap_or("");
emit(&env.id, json!({ "type": "delta", "ts": 1, "text": text }));
emit(&env.id, json!({
"type": "completed", "ts": 2,
"usage": { "input_tokens": 0, "output_tokens": 0 }
}));
}
_ => {
emit(&env.id, json!({
"type": "error", "ts": 0,
"code": "unknown_cmd",
"message": format!("cmd not implemented: {}", env.cmd)
}));
}
}
}
fn main() {
let stdin = io::stdin();
for line in stdin.lock().lines() {
let line = line.expect("stdin read error");
if line.trim().is_empty() {
continue;
}
match serde_json::from_str::<Envelope>(&line) {
Ok(env) => dispatch(&env),
Err(err) => eprintln!("parse error: {err}"),
}
}
}
Bash runtime starter
curl, python3 (JSON parsing), your Anthropic key in ANTHROPIC_KEYRun:
echo '{"v":"happi/1.0","id":"1","cmd":"anthropic.messages.create","args":["Hello"]}' | bash happi_runtime.sh
#!/usr/bin/env bash
# Minimal HAPPI/1.2 runtime in Bash.
# Calls the Anthropic REST endpoint via curl.
# Requires: curl, python3, and your key in ANTHROPIC_KEY.
set -euo pipefail
HAPPI_MODEL="${HAPPI_MODEL:-claude-opus-4-7}"
# emit <id> <type> <ts> [extra_json]
emit() {
local id="$1" type="$2" ts="$3" extra="${4-}"
printf '{"v":"happi/1.2","id":"%s","type":"%s","ts":%d%s}\n' \
"$id" "$type" "$ts" "${extra:+,$extra}"
}
# Extract a JSON field without jq
jget() { python3 -c "import sys,json; e=json.load(sys.stdin); print(e$1)"; }
jenc() { python3 -c "import sys,json; print(json.dumps(sys.stdin.read()))"; }
dispatch() {
local line="$1"
local id cmd prompt
id=$(printf '%s' "$line" | jget "['id']")
cmd=$(printf '%s' "$line" | jget "['cmd']")
prompt=$(printf '%s' "$line" | jget ".get('args',[''])[0]")
emit "$id" "started" 0
if [[ "$cmd" == anthropic.* ]]; then
local body response text in_tok out_tok prompt_json text_json
prompt_json=$(printf '%s' "$prompt" | jenc)
body=$(printf \
'{"model":"%s","max_tokens":1024,"messages":[{"role":"user","content":%s}]}' \
"$HAPPI_MODEL" "$prompt_json")
response=$(curl -sS "https://api.anthropic.com/v1/messages" \
-H "x-api-key: ${ANTHROPIC_KEY}" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
--data-binary "$body")
text=$(printf '%s' "$response" | jget "['content'][0]['text']")
in_tok=$(printf '%s' "$response" | jget "['usage']['input_tokens']")
out_tok=$(printf '%s' "$response" | jget "['usage']['output_tokens']")
text_json=$(printf '%s' "$text" | jenc)
emit "$id" "delta" 1 "\"text\":$text_json"
emit "$id" "completed" 2 \
"\"usage\":{\"input_tokens\":$in_tok,\"output_tokens\":$out_tok}"
else
local cmd_json
cmd_json=$(printf '%s' "$cmd" | jenc)
emit "$id" "error" 0 \
"\"code\":\"unknown_cmd\",\"message\":\"cmd not implemented: $cmd_json\""
fi
}
while IFS= read -r line; do
[[ -n "${line// }" ]] && dispatch "$line"
done
Conformance checklist
Run your runtime through these checks to verify it is HAPPI/1.2 compliant. A runtime that passes all items is a conformant implementation.
Envelope parsing
"v" and "id" unchanged on every emitted eventerror event (not crash) on malformed JSONargs array gracefullyEvent emission
startedcompletedcompleted includes usage.input_tokens and usage.output_tokensdelta event carries a non-empty text fieldts is monotonically non-decreasing within a single requestError handling
cmd values produce an error event, not a crasherror events include code (machine) and message (human)error events, not process exit 1Quick smoke test
# Test 1: built-in echo (no provider key needed)
echo '{"v":"happi/1.0","id":"t1","cmd":"echo","args":["hello"]}' \
| <your-runtime>
# Expect: started / delta("hello") / completed
# Test 2: unknown command — must produce error event, not crash
echo '{"v":"happi/1.0","id":"t2","cmd":"no.such.cmd","args":[]}' \
| <your-runtime>
# Expect: started / error(code="unknown_cmd")
# Test 3: two envelopes on one stdin stream
printf '%s\n%s\n' \
'{"v":"happi/1.0","id":"a","cmd":"echo","args":["first"]}' \
'{"v":"happi/1.0","id":"b","cmd":"echo","args":["second"]}' \
| <your-runtime>
# Expect: full event stream for "a" then full event stream for "b"
Built a conformant runtime? Open an issue on the GitHub repository (coming) to get it listed on the HAPPI ecosystem page. The spec is frozen at 1.0 — your implementation will not break.