A standalone Go binary that implements the forward credential proxy
component of @clef-sh/agent. The
proxy intercepts outbound HTTPS, matches requests against service
definitions served by the agent over a loopback HTTP API, and injects
credentials per the configured auth scheme.
workload ──HTTPS──▶ clef-proxy ──HTTPS (with credential)──▶ upstream
│
└──loopback HTTP──▶ @clef-sh/agent
The proxy is not installed or configured directly. The agent process
spawns it as a subprocess at startup, supervises its lifecycle, and
exposes user-facing CLI commands (clef agent serve, clef agent ca …)
that delegate to it. End users install @clef-sh/agent; npm
optionalDependencies resolution pulls in the right
@clef-sh/proxy-{platform}-{arch} package automatically.
See PROXY_PRD.md
in the clef-sh/clef repo for the full architecture.
Phase 1 — research preview. All locked Phase 1 deliverables (PRD §5.1) ship.
| Surface | Status |
|---|---|
--version, --help, ca path |
✅ |
ca export --format pem|der|der-base64 [--out <path>] |
✅ |
ca regenerate --confirm |
✅ |
| Internal agent client (Ready, Services, Secret) | ✅ |
serve lifecycle (config, CA, agent, listener, signal, drain) |
✅ |
| TLS interception (goproxy + CA Minter via SNI, IP-literal fallback) | ✅ |
| Workload auth (Proxy-Authorization Basic, Lambda-loopback bypass) | ✅ |
| Service matching (locked 0/1/N selection + X-Clef-Service) | ✅ |
| Credential injection (bearer, api_key_header, api_key_query) | ✅ |
| Host allowlist (default-deny with passthrough_hosts) | ✅ |
| Audit log emission (stdout or rotating file, JSON-line schema_version=1) | ✅ |
| Upstream proxy chaining (corporate forward proxy, NoProxy, Basic auth) | ✅ |
Lambda env auto-detection (drain default + --lambda-loopback-only) |
✅ |
Phase 2 (HTTP/2, WebSocket/SSE, wildcard hosts, multi-primitive
templates including basic auth, audit webhook, per-agent identity
via Proxy-Authorization username) is tracked in PRD §5.2 and not
in this repo yet.
make build # Build for current platform → bin/clef-proxy
make build-all # Cross-compile all five published platforms
make test # Unit tests
make test-race # Unit tests with race detector
make fmt # gofmt -w .
make clean # Remove build artifactsPure Go, CGO_ENABLED=0. Cross-compilation needs no per-target C
toolchain.
| Target | Output |
|---|---|
| macOS ARM64 (Apple Silicon) | bin/clef-proxy-darwin-arm64 |
| macOS x64 (Intel) | bin/clef-proxy-darwin-x64 |
| Linux x64 | bin/clef-proxy-linux-x64 |
| Linux ARM64 | bin/clef-proxy-linux-arm64 |
| Windows x64 | bin/clef-proxy-win32-x64.exe |
The binary is invoked by the agent. The user-facing entry points all
live on the clef agent command tree; the binary itself only exposes
the underlying surface they delegate to:
clef-proxy serve --config <path> # daemon mode
clef-proxy ca export [--format pem|der|der-base64] [--out <path>]
clef-proxy ca path # print platform-default CA dir
clef-proxy ca regenerate --confirm # destructive
clef-proxy --version # bare semver on stdout, exit 0| Variable | Purpose |
|---|---|
CLEF_PROXY_TOKEN |
Workload→proxy bearer token (operator-set) |
CLEF_PROXY_AGENT_TOKEN |
Internal proxy→agent token (agent-generated, per-process) |
CLEF_PROXY_AGENT_URL |
Agent loopback URL, e.g. http://127.0.0.1:7777 |
CLEF_PROXY_LAMBDA_LOOPBACK |
Lambda exception (only honored under AWS Lambda) |
AWS_LAMBDA_FUNCTION_NAME |
Lambda env detection (set by the runtime) |
Locked contract with the agent supervisor. Codes ≥ 7 are reserved.
| Code | Meaning |
|---|---|
| 0 | Clean exit |
| 1 | Generic / unhandled |
| 2 | Invalid config |
| 3 | Agent unreachable at startup (/v1/ready poll timeout) |
| 4 | Authentication misconfig (missing/empty internal token) |
| 5 | CA load/generate failure |
| 6 | Listener bind failure |
| Package | Platform |
|---|---|
@clef-sh/proxy-darwin-arm64 |
macOS ARM64 |
@clef-sh/proxy-darwin-x64 |
macOS x64 |
@clef-sh/proxy-linux-x64 |
Linux x64 |
@clef-sh/proxy-linux-arm64 |
Linux ARM64 |
@clef-sh/proxy-win32-x64 |
Windows x64 |
Each ships a single platform binary. npm resolves the right one via
os and cpu fields. The @clef-sh/agent package lists them all as
optionalDependencies; npm picks one at install time.
Releases are tag-driven and tokenless — pushing a v* tag triggers
.github/workflows/release.yml, which:
- Runs unit tests.
- Creates a GitHub Release with auto-generated notes.
- Cross-compiles all 5 platforms (single Linux runner pool; pure Go,
no per-target toolchain) and uploads each binary +
.sha256as release assets. - Per platform on the matching OS runner: downloads the binary,
verifies checksum, smoke-tests
--version, stamps the version intoplatforms/proxy-*/package.json, and runsnpm publish --provenance --access publicvia npm trusted- publisher OIDC (noNPM_TOKENsecret).
OIDC trusted publishing requires registering this repo + workflow as a publisher of each scoped package on npmjs.com. Steps:
- Sign in to npmjs.com with an account that has publish rights on
the
@clef-shorg. - For each of the five
@clef-sh/proxy-{platform}-{arch}packages:- Open the package's Settings → Trusted Publishers. If the package doesn't exist yet, npm creates it on first publish; you can pre-register the trusted publisher rule before the package is created.
- Add a GitHub Actions trusted publisher with:
- Repository:
clef-sh/proxy - Workflow filename:
release.yml - Environment name:
prod(matchesenvironment: prodinpublish-npm)
- Repository:
- After all five packages are configured, cut a tag:
Release workflow takes it from there.
git tag -s v0.0.1 -m "v0.0.1" git push origin v0.0.1
# Verify everything green before tagging.
make test && make test-race && make build-all
# Tag and push (signed).
git tag -s v0.0.1 -m "v0.0.1"
git push origin v0.0.1
# Watch the workflow.
gh run watchv0.0.x is the pre-confirmation cadence: every release is a candidate
that may break or be yanked while the agent team runs end-to-end smoke
tests against a real workload. Once the headline pitch is confirmed in
the wild, the next release is v0.1.0 and the cadence stabilizes.
The @clef-sh/agent package's optionalDependencies should pin the
proxy versions it's compatible with. During v0.0.x use an exact pin
("0.0.1") since 0.0.x minor bumps may be breaking. Switch to a
caret range once stable ("^0.1.0").