{"id":51063524,"url":"https://github.com/ntholm86/llm-harness-proxy","last_synced_at":"2026-06-23T04:02:53.065Z","repository":{"id":357768466,"uuid":"1232159432","full_name":"ntholm86/llm-harness-proxy","owner":"ntholm86","description":"Transparent MITM proxy that intercepts LLM traffic and writes a tamper-evident, hash-chained audit ledger before releasing the response.","archived":false,"fork":false,"pushed_at":"2026-06-20T14:33:36.000Z","size":4190,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-06-20T15:24:59.547Z","etag":null,"topics":["agent-monitoring","ai-safety","anthropic","audit-trail","autonomous-agents","earned-autonomy","fail-closed","hash-chain","llm","mitm-proxy","observability","observable-autonomy","openai","proxy","rust"],"latest_commit_sha":null,"homepage":"https://github.com/ntholm86/principles-of-earned-autonomy","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ntholm86.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-07T16:41:52.000Z","updated_at":"2026-06-20T14:33:40.000Z","dependencies_parsed_at":null,"dependency_job_id":"902b5ded-c46d-40e3-9c0a-9908e5c7c688","html_url":"https://github.com/ntholm86/llm-harness-proxy","commit_stats":null,"previous_names":["ntholm86/llm-harness-protocol","ntholm86/harness-proxy","ntholm86/llm-harness-proxy"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ntholm86/llm-harness-proxy","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ntholm86%2Fllm-harness-proxy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ntholm86%2Fllm-harness-proxy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ntholm86%2Fllm-harness-proxy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ntholm86%2Fllm-harness-proxy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ntholm86","download_url":"https://codeload.github.com/ntholm86/llm-harness-proxy/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ntholm86%2Fllm-harness-proxy/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34674702,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-23T02:00:07.161Z","response_time":65,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agent-monitoring","ai-safety","anthropic","audit-trail","autonomous-agents","earned-autonomy","fail-closed","hash-chain","llm","mitm-proxy","observability","observable-autonomy","openai","proxy","rust"],"created_at":"2026-06-23T04:02:52.341Z","updated_at":"2026-06-23T04:02:53.060Z","avatar_url":"https://github.com/ntholm86.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"﻿# llm-harness-proxy\n\nA transparent MITM proxy that writes a tamper-evident, hash-chained ledger of every LLM interaction — before the response is released to the caller.\n\nThe proxy enforces **Architectural Constraint**: an LLM response cannot reach the client unless its reasoning and actions have been durably persisted. This is a structural guarantee, not a behavioral one.\n\nThe ledger format is specified in [SPEC.md](./SPEC.md).\n\n---\n\n## Quickstart\n\n**1. Download the binary** from the latest [CI build](../../actions/workflows/build-proxy.yml):\n- `llm-harness-proxy-windows` — Windows x86_64\n- `llm-harness-proxy-linux` — Linux x86_64\n\n**2. Run the proxy:**\n\n```sh\n./llm-harness-proxy\n```\n\nThe proxy listens on `127.0.0.1:8474` by default (`HARNESS_LISTEN` to override).\n\n`HARNESS_ROOT` (the session write location) is resolved in this order:\n\n| Priority | Condition | Session location |\n|---|---|---|\n| 1 | `HARNESS_ROOT` env var is set | `$HARNESS_ROOT/sessions/` |\n| 2 | cwd is inside a git repo | `\u003crepo-root\u003e/.harness/sessions/` |\n| 3 | no git repo found | `~/.harness/sessions/` |\n\nWhen **ai-steward** manages a project it sets `HARNESS_ROOT` to the target repository root — sessions land inside that repo and can be committed alongside the code. When running standalone (as above), the proxy detects the nearest git repo automatically.\n\n**3. Point your LLM client at the proxy:**\n\n```python\n# OpenAI / Grok\nclient = OpenAI(base_url=\"http://127.0.0.1:8474/v1\", api_key=\"...\")\n\n# Anthropic\nclient = Anthropic(base_url=\"http://127.0.0.1:8474\", api_key=\"...\")\n```\n\n**4. Each call produces a session file:**\n\n```jsonc\n// .harness/sessions/\u003culid\u003e.jsonl — one line per turn\n{\n  \"v\": 1, \"seq\": 0, \"sid\": \"01KRNDE2C2DBE9AWNYPXKGSD7M\",\n  \"ts\": \"2026-05-15T08:53:17.241Z\", \"model\": \"claude-haiku-4-5\",\n  \"in\":   \"sha256:faf7bc...\",   // SHA-256 of the canonicalized request\n  \"prev\": \"sha256:000000...\",   // genesis; subsequent turns chain here\n  \"think\": null,                // extended reasoning tokens (if any)\n  \"reason\": \"\",                 // model text output\n  \"act\": {                      // tool call (if any)\n    \"name\": \"record_result\",\n    \"input\": { \"status\": \"harness-act-verified\" }\n  },\n  \"transparency\": { \"think\": false, \"act\": true }\n}\n```\n\n---\n\n## Supported providers\n\n| Provider | Endpoint | Notes |\n|---|---|---|\n| OpenAI / Grok | `/v1/chat/completions` | Streaming + buffered. `UPSTREAM_BASE_URL` to override (default: `https://api.openai.com`). |\n| Anthropic | `/v1/messages` | Streaming + buffered. `ANTHROPIC_BASE_URL` to override (default: `https://api.anthropic.com`). |\n| Gemini | `/v1beta/models/*` | Streaming + buffered. `GEMINI_BASE_URL` to override (default: `https://generativelanguage.googleapis.com`). |\n\nThe proxy is a dumb pipe: all request headers (including `Authorization` / `x-api-key`) are forwarded verbatim. No credentials are read or stored.\n\n---\n\n## Environment variables\n\n| Variable | Default | Description |\n|---|---|---|\n| `HARNESS_ROOT` | *(see below)* | Session root. If unset: git repo root → `~/.harness`. Created if absent. |\n| `HARNESS_LISTEN` | `127.0.0.1:8474` | Address to bind. |\n| `UPSTREAM_BASE_URL` | `https://api.openai.com` | Upstream for `/v1/chat/completions`. |\n| `ANTHROPIC_BASE_URL` | `https://api.anthropic.com` | Upstream for `/v1/messages`. |\n| `GEMINI_BASE_URL` | `https://generativelanguage.googleapis.com` | Upstream for `/v1beta/models/*`. |\n\n---\n\n## How it works\n\n```\nClient → llm-harness-proxy:8474 → Real LLM API\n                ↓\n         .harness/sessions/\u003culid\u003e.jsonl\n         (fsync'd before response forwarded)\n```\n\nEach session is one JSONL file named by a ULID (sortable by creation time). Each line is one turn. Consecutive turns are linked by a SHA-256 hash chain over RFC 8785 canonicalized entries — tampering or reordering any entry breaks the chain.\n\nThe `transparency` object records whether `think` and `act` carried content, enabling downstream analysis without content inspection.\n\nSee [SPEC.md](./SPEC.md) for the full protocol definition (entry format, hash chain, streaming continuations, failure semantics, conformance tiers).\n\n---\n\n## Build from source\n\nRequires Rust stable.\n\n```sh\ncd proxy-rust\ncargo test    # 15 unit tests: ledger integrity, JCS canonicalization, ULID\ncargo build --release\n```\n\nCI builds and uploads artifacts for Windows x86_64 and Linux x86_64 on every push to `proxy-rust/`.\n\n---\n\n## Design principles\n\n- **Fail-closed.** If the ledger write fails, the response is withheld. The client sees an error. The LLM cannot act without a record.\n- **Dumb pipe.** The proxy does not interpret, filter, or modify content. It captures what the model sent and what the client sent.\n- **Zero client integration.** One `base_url` change. No SDK wrapping, no library import.\n- **Single binary.** No runtime, no daemon, no configuration file.\n\n---\n\n## Documentation\n\n- [SPEC.md](./SPEC.md) — Full protocol specification (entry format, hash chain, streaming, failure semantics)\n- [docs/AAT-MAPPING.md](./docs/AAT-MAPPING.md) — Field-by-field mapping to IETF Agent Audit Trail (draft-sharif-agent-audit-trail-00)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fntholm86%2Fllm-harness-proxy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fntholm86%2Fllm-harness-proxy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fntholm86%2Fllm-harness-proxy/lists"}