Build a Runtime · HAPPI/1.2

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

started delta completed tool_call tool_result sub_request error

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

Install: pip install anthropic
Env: export your Anthropic key as ANTHROPIC_KEY
Run: 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

Install: npm install @anthropic-ai/sdk ts-node typescript
Env: export your Anthropic key as ANTHROPIC_KEY
Run: 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

No external deps for the skeleton — uses only the standard library. Wire in 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

Cargo.toml deps: 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

Requires: curl, python3 (JSON parsing), your Anthropic key in ANTHROPIC_KEY
Run: 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

Accepts valid JSON objects on stdin, one per line
Echoes "v" and "id" unchanged on every emitted event
Ignores unknown envelope fields without error
Emits error event (not crash) on malformed JSON
Supports empty args array gracefully
Handles multiple envelopes sequentially on the same stdin

Event emission

First event for each request is always started
Last event for a successful request is completed
completed includes usage.input_tokens and usage.output_tokens
Each delta event carries a non-empty text field
ts is monotonically non-decreasing within a single request
Events are flushed to stdout immediately (no line-buffering)

Error handling

Unknown cmd values produce an error event, not a crash
error events include code (machine) and message (human)
Provider HTTP errors produce error events, not process exit 1
Process exits cleanly (code 0) after stdin is closed

Quick 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.