Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
a731f34
fix: preserve provider typed Claude tools
AndrewMoryakov Jul 12, 2026
da83c66
wip: preserve local Codex and dashboard changes before upstream merge
AndrewMoryakov Jul 12, 2026
973954a
Merge remote-tracking branch 'origin/main' into integrate/upstream-20…
AndrewMoryakov Jul 12, 2026
0b43c8e
test: make docs and export e2e checks Windows-safe
AndrewMoryakov Jul 12, 2026
e6452f0
docs(spec): pxpipe safeguards & self-diagnosis design
AndrewMoryakov Jul 15, 2026
2674349
docs(spec): resolve safeguards open questions (session-only, launcher…
AndrewMoryakov Jul 15, 2026
ff7f202
docs(plan): pxpipe safeguards Phase A implementation plan
AndrewMoryakov Jul 15, 2026
aa234df
wip: checkpoint local changes before Phase A safeguards
AndrewMoryakov Jul 16, 2026
a9aa678
feat(health): pure evaluateHealth + summarizeHealth (codex-upstream c…
AndrewMoryakov Jul 16, 2026
ae54621
feat(health): rolling codex-traffic counter
AndrewMoryakov Jul 16, 2026
da13340
feat(health): buildHealthState + DashboardState.isCompressionEnabled
AndrewMoryakov Jul 16, 2026
9d64f50
feat(health): serve /healthz (200/503) + /api/health.json; feed counter
AndrewMoryakov Jul 16, 2026
3b47243
feat(health): loud startup findings banner + actionable EADDRINUSE exit
AndrewMoryakov Jul 16, 2026
a29a77b
feat(health): launcher healthcheck script + docs
AndrewMoryakov Jul 16, 2026
ae9e723
refactor(health): reuse existing getCompressionEnabled, drop duplicat…
AndrewMoryakov Jul 16, 2026
ff68af5
feat(dashboard): warn when enabling weak-reader models
AndrewMoryakov Jul 16, 2026
671e3d3
feat(dashboard): readiness-tiered model warnings (validated/below-bar…
AndrewMoryakov Jul 16, 2026
7cb5368
docs: add measurement audit and local launcher
AndrewMoryakov Aug 1, 2026
c4d920b
merge: integrate upstream v0.11.1
AndrewMoryakov Aug 1, 2026
5543b4f
fix(codex): preserve ChatGPT OAuth with OpenAI key
AndrewMoryakov Aug 1, 2026
afab0da
fix(scope): restore reset and persistent overrides
AndrewMoryakov Aug 1, 2026
a8b2c66
fix(scope): keep model chips consistent with prefix scopes
AndrewMoryakov Aug 1, 2026
ab8f597
fix(metrics): separate provider usage from Claude pricing
AndrewMoryakov Aug 1, 2026
ac549da
fix(docker): expose local dashboard health safely
AndrewMoryakov Aug 1, 2026
3388960
fix(codex): retain bypass accounting and portable launcher
AndrewMoryakov Aug 1, 2026
27db76a
docs(scope): align defaults and reset behavior
AndrewMoryakov Aug 1, 2026
75cf91e
fix: correct pricing and Codex response safety
AndrewMoryakov Aug 1, 2026
c2284e1
fix(docker): restrict dashboard proxy trust
AndrewMoryakov Aug 1, 2026
ba75b64
fix(scope): ignore corrupt persisted model scopes
AndrewMoryakov Aug 1, 2026
a7fec8b
fix(scope): preserve siblings when disabling broad scope child
AndrewMoryakov Aug 1, 2026
9b5890d
fix(metrics): attribute Gemini savings evidence
AndrewMoryakov Aug 1, 2026
d9850cf
fix(scope): turn off broad model groups completely
AndrewMoryakov Aug 1, 2026
7c10411
fix(backend): harden ingress and session accounting
AndrewMoryakov Aug 1, 2026
1c6ebb7
fix(backend): close repeat review findings
AndrewMoryakov Aug 1, 2026
0882290
fix(events): recognize legacy PID locks
AndrewMoryakov Aug 1, 2026
f231ec0
feat(node): env-driven events.jsonl rotation, retention, and fsync
AndrewMoryakov Aug 1, 2026
2e154fa
feat(dashboard): trust reverse-proxy source and allow declared origins
AndrewMoryakov Aug 21, 2026
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
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ eval/corpus/
# Bench artifacts (events.jsonl, PNG dumps, workspaces) — one dir per run
bench/runs/

# Local runtime outputs
*.log.err
*.log.out
*-debug.err
*-debug.out

# eval run artifacts (outputs, not sources)
eval/verbatim-15/out_*/
eval/verbatim-15/retest_rep*/
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,6 @@ EXPOSE 47821
VOLUME ["/data"]

HEALTHCHECK --interval=5s --timeout=2s --start-period=2s --retries=3 \
CMD node -e "const s=require('node:net').connect(process.env.PORT,'127.0.0.1');s.setTimeout(1500);s.on('connect',()=>{s.destroy();process.exit(0)});s.on('timeout',()=>process.exit(1));s.on('error',()=>process.exit(1))"
CMD node -e "fetch('http://127.0.0.1:' + process.env.PORT + '/healthz').then(r => process.exit(r.ok ? 0 : 1)).catch(() => process.exit(1))"

CMD ["node", "dist/node.js"]
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,33 @@ Same thing without `ANTHROPIC_BASE_URL`, so `/remote-control`, claude.ai
connectors, and first-party gates keep working. Full instructions in the
dashboard.

### Windows launcher and health check

This fork includes `pxpipe-run.cmd` for launching pxpipe on Windows. After it
starts, verify the local instance and routing with:

```powershell
pwsh -File scripts/pxpipe-healthcheck.ps1
```

The endpoint reports `200` when healthy; a `503` includes a routing diagnosis.
For how dashboard savings, cache tiers, and Codex rollout records are measured,
see [the measurement and calibration audit](docs/MEASUREMENT_AUDIT.md).

### Docker Compose

`docker compose up -d` publishes pxpipe only on `127.0.0.1` and makes the
dashboard plus `/healthz` available at the usual local port. The compose file
explicitly trusts only its fixed Docker bridge gateway for those routes; do
not copy that setting to a deployment whose published port is reachable from
an untrusted network. Compose also sets
`PXPIPE_ALLOW_NON_LOOPBACK_CREDENTIALS=1` because `HOST=0.0.0.0` is confined to
the container while the host port is loopback-only. Outside this bundled
topology, pxpipe refuses a non-loopback bind when it would inject a server-owned
OpenAI/Cloudflare credential or gateway header: otherwise
any reachable client could spend that credential through the unauthenticated
proxy. Set the override only when a firewall, private network, or equivalent
trusted access boundary enforces the same restriction.
## Offline export (no proxy)

You can render text, files, or diffs to PNG pages without running the proxy or
Expand Down
15 changes: 15 additions & 0 deletions compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ services:
ports:
- "127.0.0.1:${PXPIPE_PORT:-47821}:47821"
environment:
# Docker bridge requests are not loopback inside the container. The port
# remains published to host loopback only, so dashboard/health stay local.
- PXPIPE_TRUSTED_DASHBOARD_PROXY=172.30.250.1
# HOST is 0.0.0.0 inside the container, but the only host publication is
# the loopback binding above. Acknowledge that external access boundary
# so server-owned upstream credentials may be injected safely.
- PXPIPE_ALLOW_NON_LOOPBACK_CREDENTIALS=1
- PXPIPE_MODELS
- PXPIPE_DISABLE
- PXPIPE_UPSTREAM
Expand All @@ -30,6 +37,14 @@ services:
- PXPIPE_DEBUG_CAPTURE_4XX
volumes:
- pxpipe-data:/data
networks:
- pxpipe-local

volumes:
pxpipe-data:

networks:
pxpipe-local:
ipam:
config:
- subnet: 172.30.250.0/24
74 changes: 74 additions & 0 deletions docs/MEASUREMENT_AUDIT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Measurement and calibration audit

`Input reduction` is a cache-aware counterfactual, not an invoice. A Claude
row enters the measured numerator only when pxpipe has both the upstream
`usage` block and successful pre-transform `count_tokens` probes. A failed
probe receives zero credited saving. Responses/GPT rows use local tokenizer
and vision-token math and are disclosed separately as estimates.

## Cache tiers

For actual Anthropic usage pxpipe honours the server's reported cache-create
split: 5-minute writes are `1.25x`, one-hour writes are `2.0x`, and reads are
`0.1x`. Older responses may omit that split. They remain readable and use the
legacy 5-minute assumption, but the dashboard reports those tokens as
`cache_create_tier_unknown_tokens`; they are not evidence of a 5-minute TTL.
It also shows a **TTL sensitivity** number that reprices those unknown actual
creates at the 1-hour rate. That is a downside scenario for one assumption,
not a statistical confidence interval and not a complete lower bound.

The hypothetical text path's cache state cannot be observed. Its warm/cold
state follows the actual request's reported cache read and is therefore a
modelled counterfactual, even when its text token count is measured.

## Dollar display

The dollar tile prices each measured Claude row by model family using the
official first-party list price checked **2026-07-13**: Fable 5 `$10/M`, Opus
4.5–4.8 `$5/M`, Sonnet 4.5/4.6 `$3/M`, Haiku 4.5 `$1/M`; Sonnet 5 is `$2/M`
through **2026-08-31** and is scheduled to become `$3/M` on 2026-09-01.
The lookup applies that UTC date boundary automatically; it does not leave the
introductory rate active indefinitely. An exact model override still takes
precedence.
Configure a private gateway or nonstandard model explicitly before treating it
as money:

```powershell
$env:PXPIPE_MODEL_INPUT_USD_PER_MTOK = '{"claude-opus-4-8":5,"claude-fable-5":10}'
```

The value is an input-side list-price conversion, not a provider billing
export, subscription credit, or tax-inclusive invoice. Unknown models are
excluded from the dollar total and counted in the audit drawer.

## Manual calibration only

pxpipe never samples requests or silently routes traffic around compression.
To collect an observed baseline, explicitly use **Disable compression** in the
dashboard and confirm the dialog. Send comparable normal-text requests, then
enable compression and send comparable imaged requests. The toggle records
only the completed usage-bearing requests in those two in-memory phases.

The first eligible baseline row locks the comparison to one Claude model and
one `first_user_sha8` session. Rows from other models/sessions and OpenAI/Codex
rows are ignored and counted as out of scope. The result remains sequential and
observational: context size, cache warmth and user workload can still differ
between phases. Treat it as a calibration check, not a paired billing
experiment. Restarting pxpipe clears the calibration note.

## OpenAI cache diagnostics

When an OpenAI-compatible upstream reports `cache_write_tokens` under
`input_tokens_details` or `prompt_tokens_details`, pxpipe persists it on the
event as a diagnostic subset of `input_tokens`. It is never added to the input
total a second time. Cache hits (`cached_tokens`), writes, output, and reasoning
remain separately auditable.

## Codex rollout coverage

Codex provider usage is read incrementally from retained local rollout files
whose `model_provider` is `pxpipe`. The index reads only appended bytes, keeps
partial JSONL rows until completion, and rebuilds a file after truncate or
replacement. Provider-reported token records are ground truth for those
retained records; they are not proof of complete billing history when rollout
files have been deleted or are unavailable.
Loading