Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/pitot-lab.yml
Original file line number Diff line number Diff line change
Expand Up @@ -124,5 +124,7 @@ jobs:
--head "${{ github.event.pull_request.head.sha }}"
- name: Generate Types
run: bash labs/15-pitot/scripts/generate_types.sh
- name: Verify generated Python SDK syntax
run: python -m py_compile labs/15-pitot/pitot-distribution/sdk/python/pitot/types.py
- name: Verify projection and public surface
run: python -m unittest discover -s labs/15-pitot/tests -p 'test_*.py'
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
### Restructure README for faster value comprehension

- **Outcome-focused hero:** Replaces mechanism-first opening with a clear explanation of what happens to a delivery process when coding agents change.
- **Portability consequences:** Updates the portability table to describe retained operational value (e.g., "The same path from approved plan to reviewed PR") instead of just artifacts.
- **Explicit compounding:** Adds a section explaining how retained durable artifacts make the next feature easier to start without reconstructing intent from chat.
- **Reordered content:** Moves technical feature lists and installation instructions below the primary outcomes to respect evaluator attention.
8 changes: 7 additions & 1 deletion labs/15-pitot/pitot-distribution/UPSTREAM.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,16 @@
"protocol/framing.go": "d4409314b72e09cfd472ad9a21d4c7a223b4341b26f58f6062a7c899e3f87482",
"protocol/framing_test.go": "9fcb13767fdcc7129d2c87bc2133a5800c69d6ac0166016dc266dca5fcfaa1c5",
"schema/schema.go": "fd5c3b76979c88aeed75fadb7e3c94abcad62e067d77595f021fb422a60f2211",
"sdk/python/pitot/__init__.py": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"sdk/python/pitot/types.py": "c9a7221f1ad6627f152f26148155d3c74f249c52262c73a515251f469e8eb4ad",
"sdk/python/pyproject.toml": "3f42de8223640978ad88e3f7b4ad1464053c43a393f0edf48445cacd31dd537c",
"sdk/typescript/package.json": "c26c726559ff0bc7c5d92b68303efc3c35314613248fe346fa125aea06c8dba6",
"sdk/typescript/src/index.ts": "de43e6654eac51afd09a3a74c4c6992dcf2306d6c41b9be626ded1c6d6cc7833",
"sdk/typescript/src/pitot.ts": "9c243824cbb7edc54b1e125abfd828bf2ed77e7151a0bd5c5d4f63e81ca9b00c",
"sdk/typescript/tsconfig.json": "e4d7ecb203fcb7d93cd9b9fb235d7fd75d1b6fb2b28eff773f4aecfdc1924d5d",
"sensor/decode_fuzz_test.go": "6f3412865c16e3314980a369c36f1f26ba36a991c8b4a8a9d3b776ad9c0de2b0",
"sensor/sensor.go": "939e146eaa51906972f98cf4615747eb75811b0c54d467a938825750336abeae",
"sensor/sensor_test.go": "ea9a58d45ad56d29214a40fb2cfa935e769f85334afcb1856a20fb938d486245",
"types/ts/pitot.ts": "9c243824cbb7edc54b1e125abfd828bf2ed77e7151a0bd5c5d4f63e81ca9b00c",
"windtunnel/doc.go": "44e0bcde632da73e1f8b98beade3a34ca8e0d0ea79cdfb91d131de290b164fc4",
"windtunnel/windtunnel_test.go": "1c8b6c5d56ff5c4e66403baeae0d98108255d153c1275572b8c68e333e091493"
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
### Restructure public distribution as a polyglot SDK

The Pitot distribution surface has been reorganized to prevent the Go module root from becoming cluttered with multi-language build configurations. Generated TypeScript and Python primitives are now strictly isolated inside an `sdk/` directory.

- **Go**: Remains at the root of the repository (`go.mod`, `go.sum`).
- **TypeScript**: Housed in `sdk/typescript/`, complete with its own `package.json` and `tsconfig.json`.
- **Python**: Housed in `sdk/python/`, complete with a `pyproject.toml` and autogenerated types.

This structure allows downstream users to seamlessly import the exact Pitot SDK they need for their environment without dependency conflict or configuration ambiguity.
Empty file.
307 changes: 307 additions & 0 deletions labs/15-pitot/pitot-distribution/sdk/python/pitot/types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,307 @@
from dataclasses import dataclass
from typing import Any, TypeVar, Type, cast


T = TypeVar("T")


def from_str(x: Any) -> str:
assert isinstance(x, str)
return x


def from_none(x: Any) -> Any:
assert x is None
return x


def from_union(fs, x):
for f in fs:
try:
return f(x)
except:
pass
assert False


def from_int(x: Any) -> int:
assert isinstance(x, int) and not isinstance(x, bool)
return x


def to_class(c: Type[T], x: Any) -> dict:
assert isinstance(x, c)
return cast(Any, x).to_dict()


@dataclass
class BoundaryFault:
host: str
pitot_version: str
reason: str
type: str
action_id: str | None = None

@staticmethod
def from_dict(obj: Any) -> 'BoundaryFault':
assert isinstance(obj, dict)
host = from_str(obj.get("host"))
pitot_version = from_str(obj.get("pitot_version"))
reason = from_str(obj.get("reason"))
type = from_str(obj.get("type"))
action_id = from_union([from_str, from_none], obj.get("action_id"))
return BoundaryFault(host, pitot_version, reason, type, action_id)

def to_dict(self) -> dict:
result: dict = {}
result["host"] = from_str(self.host)
result["pitot_version"] = from_str(self.pitot_version)
result["reason"] = from_str(self.reason)
result["type"] = from_str(self.type)
if self.action_id is not None:
result["action_id"] = from_union([from_str, from_none], self.action_id)
return result


@dataclass
class ControlRequested:
action_id: str
kind: str
pitot_version: str
type: str
data: Any = None

@staticmethod
def from_dict(obj: Any) -> 'ControlRequested':
assert isinstance(obj, dict)
action_id = from_str(obj.get("action_id"))
kind = from_str(obj.get("kind"))
pitot_version = from_str(obj.get("pitot_version"))
type = from_str(obj.get("type"))
data = obj.get("data")
return ControlRequested(action_id, kind, pitot_version, type, data)

def to_dict(self) -> dict:
result: dict = {}
result["action_id"] = from_str(self.action_id)
result["kind"] = from_str(self.kind)
result["pitot_version"] = from_str(self.pitot_version)
result["type"] = from_str(self.type)
if self.data is not None:
result["data"] = self.data
return result


@dataclass
class ControlResponse:
action_id: str
controller_id: str
outcome: str
pitot_version: str
type: str
message: str | None = None

@staticmethod
def from_dict(obj: Any) -> 'ControlResponse':
assert isinstance(obj, dict)
action_id = from_str(obj.get("action_id"))
controller_id = from_str(obj.get("controller_id"))
outcome = from_str(obj.get("outcome"))
pitot_version = from_str(obj.get("pitot_version"))
type = from_str(obj.get("type"))
message = from_union([from_str, from_none], obj.get("message"))
return ControlResponse(action_id, controller_id, outcome, pitot_version, type, message)

def to_dict(self) -> dict:
result: dict = {}
result["action_id"] = from_str(self.action_id)
result["controller_id"] = from_str(self.controller_id)
result["outcome"] = from_str(self.outcome)
result["pitot_version"] = from_str(self.pitot_version)
result["type"] = from_str(self.type)
if self.message is not None:
result["message"] = from_union([from_str, from_none], self.message)
return result


@dataclass
class Action:
id: str
kind: str

@staticmethod
def from_dict(obj: Any) -> 'Action':
assert isinstance(obj, dict)
id = from_str(obj.get("id"))
kind = from_str(obj.get("kind"))
return Action(id, kind)

def to_dict(self) -> dict:
result: dict = {}
result["id"] = from_str(self.id)
result["kind"] = from_str(self.kind)
return result


@dataclass
class Content:
mode: str
full: Any = None
sha256: str | None = None

@staticmethod
def from_dict(obj: Any) -> 'Content':
assert isinstance(obj, dict)
mode = from_str(obj.get("mode"))
full = obj.get("full")
sha256 = from_union([from_str, from_none], obj.get("sha256"))
return Content(mode, full, sha256)

def to_dict(self) -> dict:
result: dict = {}
result["mode"] = from_str(self.mode)
if self.full is not None:
result["full"] = self.full
if self.sha256 is not None:
result["sha256"] = from_union([from_str, from_none], self.sha256)
return result


@dataclass
class Host:
name: str
adapter_version: str | None = None

@staticmethod
def from_dict(obj: Any) -> 'Host':
assert isinstance(obj, dict)
name = from_str(obj.get("name"))
adapter_version = from_union([from_str, from_none], obj.get("adapter_version"))
return Host(name, adapter_version)

def to_dict(self) -> dict:
result: dict = {}
result["name"] = from_str(self.name)
if self.adapter_version is not None:
result["adapter_version"] = from_union([from_str, from_none], self.adapter_version)
return result


@dataclass
class Observation:
fidelity: str
source: str

@staticmethod
def from_dict(obj: Any) -> 'Observation':
assert isinstance(obj, dict)
fidelity = from_str(obj.get("fidelity"))
source = from_str(obj.get("source"))
return Observation(fidelity, source)

def to_dict(self) -> dict:
result: dict = {}
result["fidelity"] = from_str(self.fidelity)
result["source"] = from_str(self.source)
return result


@dataclass
class Usage:
input_tokens: int
output_tokens: int

@staticmethod
def from_dict(obj: Any) -> 'Usage':
assert isinstance(obj, dict)
input_tokens = from_int(obj.get("input_tokens"))
output_tokens = from_int(obj.get("output_tokens"))
return Usage(input_tokens, output_tokens)

def to_dict(self) -> dict:
result: dict = {}
result["input_tokens"] = from_int(self.input_tokens)
result["output_tokens"] = from_int(self.output_tokens)
return result


@dataclass
class Event:
host: Host
observation: Observation
pitot_version: str
type: str
action: Action | None = None
content: Content | None = None
id: str | None = None
session_id: str | None = None
time: str | None = None
usage: Usage | None = None

@staticmethod
def from_dict(obj: Any) -> 'Event':
assert isinstance(obj, dict)
host = Host.from_dict(obj.get("host"))
observation = Observation.from_dict(obj.get("observation"))
pitot_version = from_str(obj.get("pitot_version"))
type = from_str(obj.get("type"))
action = from_union([Action.from_dict, from_none], obj.get("action"))
content = from_union([Content.from_dict, from_none], obj.get("content"))
id = from_union([from_str, from_none], obj.get("id"))
session_id = from_union([from_str, from_none], obj.get("session_id"))
time = from_union([from_str, from_none], obj.get("time"))
usage = from_union([Usage.from_dict, from_none], obj.get("usage"))
return Event(host, observation, pitot_version, type, action, content, id, session_id, time, usage)

def to_dict(self) -> dict:
result: dict = {}
result["host"] = to_class(Host, self.host)
result["observation"] = to_class(Observation, self.observation)
result["pitot_version"] = from_str(self.pitot_version)
result["type"] = from_str(self.type)
if self.action is not None:
result["action"] = from_union([lambda x: to_class(Action, x), from_none], self.action)
if self.content is not None:
result["content"] = from_union([lambda x: to_class(Content, x), from_none], self.content)
if self.id is not None:
result["id"] = from_union([from_str, from_none], self.id)
if self.session_id is not None:
result["session_id"] = from_union([from_str, from_none], self.session_id)
if self.time is not None:
result["time"] = from_union([from_str, from_none], self.time)
if self.usage is not None:
result["usage"] = from_union([lambda x: to_class(Usage, x), from_none], self.usage)
return result


@dataclass
class Types:
boundary_fault: BoundaryFault
control_requested: ControlRequested
control_response: ControlResponse
event: Event

@staticmethod
def from_dict(obj: Any) -> 'Types':
assert isinstance(obj, dict)
boundary_fault = BoundaryFault.from_dict(obj.get("boundary_fault"))
control_requested = ControlRequested.from_dict(obj.get("control_requested"))
control_response = ControlResponse.from_dict(obj.get("control_response"))
event = Event.from_dict(obj.get("event"))
return Types(boundary_fault, control_requested, control_response, event)

def to_dict(self) -> dict:
result: dict = {}
result["boundary_fault"] = to_class(BoundaryFault, self.boundary_fault)
result["control_requested"] = to_class(ControlRequested, self.control_requested)
result["control_response"] = to_class(ControlResponse, self.control_response)
result["event"] = to_class(Event, self.event)
return result


def types_from_dict(s: Any) -> Types:
return Types.from_dict(s)


def types_to_dict(x: Types) -> Any:
return to_class(Types, x)
18 changes: 18 additions & 0 deletions labs/15-pitot/pitot-distribution/sdk/python/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"

[project]
name = "pitot"
version = "0.1.0"
description = "Pitot: The passive, protocol-first measurement boundary for coding agents."
authors = [
{ name = "Operator Stack" }
]
license = { text = "MIT" }
requires-python = ">=3.8"
dependencies = []

[project.urls]
Homepage = "https://github.com/operatorstack/pitot"
Repository = "https://github.com/operatorstack/pitot"
25 changes: 25 additions & 0 deletions labs/15-pitot/pitot-distribution/sdk/typescript/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"name": "@operatorstack/pitot",
"version": "0.1.0",
"description": "Pitot: The passive, protocol-first measurement boundary for coding agents.",
"main": "src/index.js",
"types": "src/index.d.ts",
"files": [
"src/**/*.ts",
"src/**/*.js",
"src/**/*.d.ts"
],
"scripts": {
"build": "tsc"
},
"repository": {
"type": "git",
"url": "https://github.com/operatorstack/pitot.git",
"directory": "sdk/typescript"
},
"author": "Operator Stack",
"license": "MIT",
"devDependencies": {
"typescript": "^5.0.0"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./pitot";
Loading
Loading