diff --git a/.github/assets/banner-dark.svg b/.github/assets/banner-dark.svg new file mode 100644 index 0000000..37ffa37 --- /dev/null +++ b/.github/assets/banner-dark.svg @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + k + + + kiroxy + + + Self-hosted AI proxy. One binary. Zero telemetry. + + + + + + 23,810 req/s + ~22 MiB binary + Go 1.26 + + + + + diff --git a/.github/assets/banner-light.svg b/.github/assets/banner-light.svg new file mode 100644 index 0000000..c65d50b --- /dev/null +++ b/.github/assets/banner-light.svg @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + k + + + kiroxy + + + Self-hosted AI proxy. One binary. Zero telemetry. + + + + + + 23,810 req/s + ~22 MiB binary + Go 1.26 + + + + + diff --git a/.github/assets/demo.svg b/.github/assets/demo.svg new file mode 100644 index 0000000..8803dec --- /dev/null +++ b/.github/assets/demo.svg @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + kiroxy β€” Quick Start + + + + + # Install kiroxy + + + $ + curl -sSL https://github.com/nopperabbo/kiroxy/releases/download/v1.4.0/kiroxy_1.4.0_Darwin_arm64.tar.gz | tar xz + + + + + # Start the proxy + + + $ + ./kiroxy serve + + + {"time":"2026-05-23T10:00:00Z","level":"INFO","msg":"kiroxy listening","addr":"http://127.0.0.1:8787"} + + + + + # Point Claude Code at kiroxy + + + $ + export ANTHROPIC_BASE_URL=http://127.0.0.1:8787 + + + $ + claude + + + + + # Test with curl + + + $ + curl -sS http://127.0.0.1:8787/v1/messages \ + -H "Content-Type: application/json" \ + -d '{"model":"claude-sonnet-4-5","max_tokens":64,"messages":[{"role":"user","content":"Hi"}]}' + + + {"content":[{"type":"text","text":"Hello! How can I help you today?"}],"model":"claude-sonnet-4-5",...} + + + $ + + + + + diff --git a/.github/assets/social-preview.png b/.github/assets/social-preview.png new file mode 100644 index 0000000..89dce1a Binary files /dev/null and b/.github/assets/social-preview.png differ diff --git a/.github/assets/social-preview.svg b/.github/assets/social-preview.svg new file mode 100644 index 0000000..6040a3e --- /dev/null +++ b/.github/assets/social-preview.svg @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + k + + + kiroxy + + + Self-hosted AI proxy. One endpoint, every model. + + + + MIT Licensed + Single Binary + ~30 MiB Docker + 23,810 rps + + + + + + + + + + + + diff --git a/.github/release.yml b/.github/release.yml new file mode 100644 index 0000000..dba677c --- /dev/null +++ b/.github/release.yml @@ -0,0 +1,31 @@ +changelog: + exclude: + labels: + - dependencies + - chore + authors: + - dependabot + - github-actions + categories: + - title: "πŸš€ Features" + labels: + - enhancement + - feat + - title: "πŸ› Bug Fixes" + labels: + - bug + - fix + - title: "πŸ”’ Security" + labels: + - security + - title: "πŸ“– Documentation" + labels: + - documentation + - docs + - title: "πŸ—οΈ Infrastructure" + labels: + - ci + - infrastructure + - title: "🧹 Other Changes" + labels: + - "*" diff --git a/.goreleaser.yml b/.goreleaser.yml index 337b32a..a59174b 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -128,4 +128,14 @@ release: ./kiroxy version ``` + ```bash + # Or via Docker + docker pull ghcr.io/nopperabbo/kiroxy:{{ .Version }} + ``` + Artefact checksums: `kiroxy_{{ .Version }}_checksums.txt` (SHA-256). + Signatures: each artefact has a `.sig` + `.cert` file for [cosign](https://docs.sigstore.dev/) verification. + + --- + + **Links:** [Documentation](https://nopperabbo.github.io/kiroxy/) Β· [Discussions](https://github.com/nopperabbo/kiroxy/discussions) Β· [Sponsor](https://github.com/sponsors/nopperabbo) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4531de4..2a6b834 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,142 +1,177 @@ # Contributing to kiroxy -Thanks for taking interest. kiroxy is a single-user, self-hosted tool maintained by [@nopperabbo](https://github.com/nopperabbo); the project is public so others can audit, fork, and learn from it. Outside contributions are welcome but lightly gated β€” please read this document before opening a PR. +
+
+ Thanks for taking interest in kiroxy. +
+ Outside contributions are welcome but lightly gated β€” please read this document before opening a PR. +
+
+
-## Project Philosophy +--- -kiroxy does **one thing well**: turn a Kiro IDE subscription into an Anthropic Messages API endpoint. We deliberately **do not** want to become: +## Philosophy -- A multi-tenant gateway (use [LiteLLM](https://github.com/BerriAI/litellm) or [Portkey](https://github.com/Portkey-AI/gateway)) -- A multi-provider router (Gemini, OpenAI, etc.) -- A SaaS service -- A general-purpose proxy framework +kiroxy does **one thing well**: turn a Kiro IDE subscription into an Anthropic Messages API endpoint. -If your contribution moves the project toward those directions, it will likely be rejected. Open an issue first to discuss scope. +We deliberately **do not** want to become: + +| ❌ Not this | βœ… Use instead | +|:---|:---| +| Multi-tenant gateway | [LiteLLM](https://github.com/BerriAI/litellm), [Portkey](https://github.com/Portkey-AI/gateway) | +| Multi-provider router | [OpenRouter](https://openrouter.ai) | +| SaaS service | β€” | +| General-purpose proxy framework | [Kong](https://github.com/Kong/kong), [Envoy](https://github.com/envoyproxy/envoy) | + +If your contribution moves toward those directions, it will likely be rejected. **Open an issue first** to discuss scope. + +--- ## Before You Open a PR -1. **Open an issue first** for anything beyond a typo fix or one-line bug. Sync on the approach. -2. **Check the BACKLOG.md** β€” your idea may already be planned, deferred, or explicitly rejected with reasoning. -3. **Read `docs/ARCHITECTURE.md`** β€” the engineering overview explains the boundaries and constraints. -4. **Read `CHANGELOG.md`** β€” recent changes reveal the project's current direction and conventions. +1. **Open an issue first** for anything beyond a typo fix +2. **Check [`BACKLOG.md`](BACKLOG.md)** β€” your idea may already be planned or explicitly rejected +3. **Read [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md)** β€” understand the boundaries +4. **Read [`CHANGELOG.md`](CHANGELOG.md)** β€” recent changes reveal current direction + +--- ## Development Setup ### Prerequisites -- **Go 1.26+** with `GOEXPERIMENT=jsonv2` enabled -- **Node 20+** + **pnpm 9+** (for the Mansion dashboard) -- **Astro 5+** (for `web/landing/`) -- **Python 3.10+** (only if working on the onboarder tool) -- **Make** (or run commands directly from the Makefile) +| Tool | Version | Purpose | +|:---|:---|:---| +| Go | 1.26+ | Backend (`GOEXPERIMENT=jsonv2` required) | +| Node | 20+ | Dashboard + landing page | +| pnpm | 9+ | Package manager | +| Make | any | Build orchestration | -### Build +### Build & Run ```bash # Backend -GOEXPERIMENT=jsonv2 go build -o ./kiroxy ./cmd/kiroxy - -# Mansion dashboard (rebuild before binary if you change Svelte source) -cd internal/server/mansion/client -pnpm install -pnpm run build +make build # or: GOEXPERIMENT=jsonv2 go build -o ./kiroxy ./cmd/kiroxy -# Landing page (independent of binary) -cd web/landing -pnpm install -pnpm run build # output to web/landing/dist/ +# Dashboard (rebuild before binary if you change Svelte source) +cd internal/server/mansion/client && pnpm install && pnpm run build -# Run all tests -go test ./... +# Landing page +cd web/landing && pnpm install && pnpm run build -# Lint -gofmt -d . -go vet ./... +# Run +./kiroxy serve +open http://localhost:8787/dashboard-mansion ``` -### Run Locally +### Quality Gates ```bash -./kiroxy serve -port 8787 -# Health check -curl http://localhost:8787/healthz -# Dashboard -open http://localhost:8787/dashboard-mansion +make gate # fmt + vet + build + test (required before commits) +make test-race # race detector +make lint # golangci-lint (25+ linters) +make bench # performance benchmarks ``` +--- + ## PR Guidelines ### Commit Messages -Follow conventional commits: `(): ` +[Conventional Commits](https://www.conventionalcommits.org/): `(): ` -Types: `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `chore`, `polish` +**Types:** `feat` Β· `fix` Β· `docs` Β· `style` Β· `refactor` Β· `perf` Β· `test` Β· `chore` Β· `polish` -Scopes vary by area: -- `kiroclient`, `pool`, `messages`, `auth` β€” backend -- `mansion` β€” dashboard -- `landing` or `web` β€” landing page -- `docs`, `ci`, `gitignore` β€” meta +**Scopes:** -Examples: -- `feat(mansion): make logs histogram bins clickable` -- `fix(pool): cool down failed accounts during rotation` -- `polish(landing): hero topology pulse animation` +| Scope | Area | +|:---|:---| +| `kiroclient`, `pool`, `messages`, `auth` | Backend | +| `mansion` | Dashboard | +| `landing`, `web` | Landing page | +| `docs`, `ci` | Meta | -### Commit Hygiene - -- **One logical change per commit.** Don't bundle a feature with a refactor. -- **Keep dependencies minimal.** No new npm or Go modules without discussion in the issue. -- **No build artifacts.** `dist/`, `node_modules/`, and binaries are gitignored β€” keep them that way. +**Examples:** +``` +feat(mansion): make logs histogram bins clickable +fix(pool): cool down failed accounts during rotation +polish(landing): hero topology pulse animation +``` ### Code Style -**Go:** -- `gofmt` everything (CI will fail otherwise) -- Use `slog` for structured logging, not `fmt.Println` -- Prefer typed errors with `errors.Is/As` over string matching +
+Go + +- `gofmt` everything (CI enforces) +- Use `slog` for structured logging +- Prefer typed errors with `errors.Is/As` - Tests live alongside source: `foo.go` + `foo_test.go` -**TypeScript / Svelte:** -- Run `pnpm exec svelte-check` before committing β€” 0 errors required -- Use `$state` / `$derived` runes (Svelte 5), not legacy `let` / `$:` syntax +
+ +
+TypeScript / Svelte + +- Run `pnpm exec svelte-check` β€” 0 errors required +- Use `$state` / `$derived` runes (Svelte 5) - No Tailwind, no shadcn, no icon libraries β€” inline SVG only -- Brand identity is locked: warm charcoal + amber, JetBrains Mono + Inter, hairline borders, max border-radius 6px +- Brand identity is locked (see below) + +
+ +
+CSS / Brand Identity -**CSS:** - Use `--c-*` design tokens from `tokens.css` β€” never hard-code colors -- The amber budget has 5 roles: wordmark cursor, live dot, primary CTA, keyboard pills, section underlines. Adding a 6th requires retiring one and justifying the swap. -- Motion budget: 4 ambient idle-loop animations max. See `motion-budget.css`. +- **Palette:** warm charcoal + aged-brass amber +- **Typography:** JetBrains Mono (display) + Inter (text) +- **Borders:** hairline, max `border-radius: 6px` +- **Amber budget:** 5 roles only (wordmark cursor, live dot, primary CTA, keyboard pills, section underlines). Adding a 6th requires retiring one. +- **Motion budget:** 4 ambient idle-loop animations max + +
### Tests -- **Backend:** Go unit tests for any logic change. Integration tests (using real or mocked Kiro endpoint) for protocol changes. -- **Frontend:** Visual changes verified via Playwright DOM probes; the multimodal review path is encouraged but not required. -- **Mobile:** Test at iPhone 13 emulation (390px viewport) β€” Pool view must stay under 6000px height. +- **Backend:** Unit tests for any logic change. Integration tests for protocol changes. +- **Frontend:** Playwright DOM probes for visual changes. +- **Mobile:** Test at iPhone 13 (390px viewport). -## What Counts as a Good First Issue +--- -If you want to contribute but don't have a specific feature in mind: +## Good First Issues -- Check issues labeled [`good first issue`](https://github.com/nopperabbo/kiroxy/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) +- Issues labeled [`good first issue`](https://github.com/nopperabbo/kiroxy/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) - Add a missing test for a function in `internal/` - Improve a documentation page in `docs/` -- Translate a section of the landing page (currently English-only) -- Add a sample integration in `docs/SAMPLE_RUN.md` for a client kiroxy hasn't been tested with +- Add a sample integration for an untested client + +--- ## What Will Be Closed -- PRs that change the project scope (multi-tenant, multi-provider, SaaS direction) -- PRs adding new dependencies without prior issue discussion -- PRs introducing UI frameworks (Tailwind, shadcn, etc.) -- PRs with build artifacts committed -- PRs without a corresponding issue for non-trivial changes -- PRs that violate the brand identity / motion budget without justification +- ❌ PRs that change project scope (multi-tenant, multi-provider, SaaS) +- ❌ PRs adding dependencies without prior issue discussion +- ❌ PRs introducing UI frameworks (Tailwind, shadcn, etc.) +- ❌ PRs with build artifacts committed +- ❌ PRs without a corresponding issue for non-trivial changes +- ❌ PRs violating brand identity / motion budget without justification + +--- ## License -By contributing, you agree your contributions will be licensed under the [MIT License](LICENSE). The `NOTICE` file tracks meaningful upstream attributions. +By contributing, you agree your contributions will be licensed under the [MIT License](LICENSE). -## Questions? +--- -Open a [Discussion](https://github.com/nopperabbo/kiroxy/discussions) (Q&A category) or file an [Issue](https://github.com/nopperabbo/kiroxy/issues). For sensitive matters, see [SECURITY.md](SECURITY.md). + diff --git a/README.md b/README.md index cb0a64c..4220125 100644 --- a/README.md +++ b/README.md @@ -1,513 +1,329 @@ -# kiroxy - -[![CI](https://github.com/nopperabbo/kiroxy/actions/workflows/ci.yml/badge.svg)](https://github.com/nopperabbo/kiroxy/actions/workflows/ci.yml) -[![CodeQL](https://github.com/nopperabbo/kiroxy/actions/workflows/codeql.yml/badge.svg)](https://github.com/nopperabbo/kiroxy/actions/workflows/codeql.yml) -[![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/nopperabbo/kiroxy/badge)](https://scorecard.dev/viewer/?uri=github.com/nopperabbo/kiroxy) -[![codecov](https://codecov.io/gh/nopperabbo/kiroxy/graph/badge.svg)](https://codecov.io/gh/nopperabbo/kiroxy) -[![Release](https://img.shields.io/github/v/release/nopperabbo/kiroxy?style=flat-square)](https://github.com/nopperabbo/kiroxy/releases/latest) -[![License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)](LICENSE) -[![Go Version](https://img.shields.io/github/go-mod/go-version/nopperabbo/kiroxy?style=flat-square)](go.mod) -[![GHCR](https://img.shields.io/badge/container-ghcr.io-blue?style=flat-square&logo=docker)](https://github.com/nopperabbo/kiroxy/pkgs/container/kiroxy) -[![Issues](https://img.shields.io/github/issues/nopperabbo/kiroxy?style=flat-square)](https://github.com/nopperabbo/kiroxy/issues) -[![Discussions](https://img.shields.io/github/discussions/nopperabbo/kiroxy?style=flat-square)](https://github.com/nopperabbo/kiroxy/discussions) -[![Sponsor](https://img.shields.io/github/sponsors/nopperabbo?style=flat-square)](https://github.com/sponsors/nopperabbo) - -A single-user, self-hosted proxy that exposes your Kiro IDE subscription (Amazon Q Developer / AWS CodeWhisperer) as an **Anthropic Messages API** endpoint. Point your Claude Code, Cursor, or any Anthropic-compatible client at kiroxy, and it forwards requests to Kiro using your own credentials. - -**Status:** v1.4.0 β€” public release, MIT-licensed. See [`CHANGELOG.md`](CHANGELOG.md) for release notes, [`ROADMAP.md`](ROADMAP.md) for what's next, [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) for the engineering overview, and [`docs/TROUBLESHOOTING.md`](docs/TROUBLESHOOTING.md) for operator diagnostics. - ---- - -## What it looks like - -The bundled **Mansion** dashboard ships in the same binary at `/dashboard-mansion`. Seven views, dark + light themes, mobile-responsive, no external CDN. - -### Live request stream - -Real-time SSE feed of every request through the pool. Click a row for a 4-tab drill-down (request, response, account, timing). Time-range picker, sort, search-scope toggle, CSV export. - -![Live request stream](docs/screenshots/dashboard-live.png) - -### Metrics - -3 time-series charts (req/min, latency p50/p95/p99, error rate), 4 top-N tables (endpoints, slowest paths, errors, clients), status-code stacked bar, and 2 SLO gauges with zone gradients. - -![Metrics dashboard](docs/screenshots/dashboard-metrics.png) - -### Account pool - -78-account density visualization with anomaly emphasis (amber border on accounts crossing 1% error rate), cooldown wash, idle dim. Pool minimap above for at-a-glance health. - -![Account pool](docs/screenshots/dashboard-pool.png) - -### Logs - -60-bin volume histogram (clickable to filter time window), multi-select level chips, facets sidebar, JSONL export, wrap toggle. - -![Logs view](docs/screenshots/dashboard-logs.png) - -### Light theme - -Token-driven theming with WCAG AA contrast in both schemes. Switch via Settings β†’ Theme. - -![Settings β€” light theme](docs/screenshots/dashboard-settings-light.png) - -### Mobile (iPhone 13) - -All 7 views adapt to 390px CSS viewport. Pool collapses to 2-line cards with sticky headers, Live stream uses vertical card layout, tap targets β‰₯44px, no horizontal scroll. - -

- Mobile dashboard +

+ + + + + + kiroxy + + + +
+ +

+ CI +   + Release +   + Coverage +   + OpenSSF Scorecard +   + License

---- - -## Installation - -Three ways to get kiroxy running. **Pre-built binary** is the fastest; -**`go install`** is the most flexible. - -### 1. Pre-built binary (recommended) - -Pre-built tarballs for Linux and macOS (amd64 + arm64) attach to every -[GitHub Release](../../releases/latest). Each archive ships the binary -plus `LICENSE`, `NOTICE`, `README.md`, `CHANGELOG.md`, -`docs/ARCHITECTURE.md`, `docs/TROUBLESHOOTING.md`, and `docs/OPENCODE.md`. -A SHA-256 checksums file (`kiroxy__checksums.txt`) verifies -download integrity. - -```bash -# Pick the matching Os_Arch β€” Linux_amd64, Linux_arm64, Darwin_amd64, Darwin_arm64. -VERSION=1.4.0 -OS_ARCH=Linux_amd64 # or Darwin_arm64, etc. - -curl -sSL -o kiroxy.tar.gz \ - "https://github.com/nopperabbo/kiroxy/releases/download/v${VERSION}/kiroxy_${VERSION}_${OS_ARCH}.tar.gz" -curl -sSL -o checksums.txt \ - "https://github.com/nopperabbo/kiroxy/releases/download/v${VERSION}/kiroxy_${VERSION}_checksums.txt" - -# Verify the archive matches the published checksum. -grep " kiroxy_${VERSION}_${OS_ARCH}.tar.gz$" checksums.txt | shasum -a 256 -c - - -tar -xzf kiroxy.tar.gz -./kiroxy version -``` - -### 2. `go install` - -Requires [Go 1.26+](https://go.dev/dl/) (kiroxy uses `encoding/json/v2` -via `GOEXPERIMENT=jsonv2`). - -```bash -GOEXPERIMENT=jsonv2 go install github.com/nopperabbo/kiroxy/cmd/kiroxy@v1.4.0 -kiroxy version -``` - -The binary lands in `$(go env GOPATH)/bin/kiroxy` (typically -`~/go/bin/kiroxy`). Make sure `$GOPATH/bin` is on your `$PATH`. - -### 3. Build from source - -For development work or if you want to inspect/modify the code first. -Covered in the [Five-minute quickstart](#five-minute-quickstart) below. -`make build` pins `GOEXPERIMENT=jsonv2` and stamps `main.version` from -`git describe`. +

+ Quick Start Β· + Architecture Β· + Troubleshooting Β· + Discussions Β· + Changelog +

-### 4. Run from Docker +
-Covered in the [Run with Docker](#run-with-docker) section below. `gcr.io` -or `ghcr.io` image hosting is on the roadmap; for now, build locally with -`make docker-build`. +
---- +## What is kiroxy? -## Five-minute quickstart +A single-binary, self-hosted proxy that exposes your **Kiro IDE subscription** as a standard **Anthropic Messages API** endpoint. Point Claude Code, Cursor, or any Anthropic-compatible client at kiroxy β€” it handles credential pooling, token refresh, and request routing transparently. -### 1. Prereqs +
-- **Go 1.26+** (kiroxy uses `encoding/json/v2` via `GOEXPERIMENT=jsonv2`) -- **A Kiro account** β€” either: - - the `kiro-cli` tool logged in (kiroxy can read its SQLite credentials directly), or - - you're running Kiro IDE and have `~/.aws/sso/cache/kiro-auth-token.json`, or - - you'll use `kiroxy add-account` to go through the AWS Builder ID device-code flow (M9, coming soon) +
+ kiroxy demo +
-### 2. Build +
-```bash -git clone -cd kiroxy -make build # or: GOEXPERIMENT=jsonv2 go build -o kiroxy ./cmd/kiroxy -``` +## Why Kiroxy? -### 3. Configure + + + + + + + + + +
+

⚑ Blazing fast

+

23,810 req/s on a single core. Zero-copy SSE streaming. No GC pauses in the hot path.

+
+

πŸ“¦ Single binary

+

One go build, one file, done. No runtime, no sidecar, no config server.

+
+

🏠 Truly self-hosted

+

Your credentials never leave your machine. Zero telemetry, zero phone-home.

+
+

πŸ”„ Drop-in API

+

Standard Anthropic Messages API β€” existing SDKs and tools work unchanged.

+
-Pick **one** of two credential sources: +
-**Option A β€” you already have kiro-cli installed and logged in** (easiest): +## How it compares -```bash -export KIROXY_KIRO_DB_PATH="$HOME/Library/Application Support/kiro-cli/data.sqlite3" # macOS -# or: export KIROXY_KIRO_DB_PATH="$HOME/.local/share/kiro-cli/data.sqlite3" # Linux -``` +| | kiroxy | LiteLLM | One-API | OpenRouter | +|:---|:---:|:---:|:---:|:---:| +| Self-hosted | βœ… | βœ… | βœ… | ❌ | +| Single binary | βœ… | ❌ | ❌ | β€” | +| Zero dependencies | βœ… | ❌ | ❌ | β€” | +| Kiro IDE support | βœ… | ❌ | ❌ | ❌ | +| Multi-account pool | βœ… | ❌ | βœ… | β€” | +| Memory footprint | ~30 MiB | ~500 MiB | ~200 MiB | β€” | +| No telemetry | βœ… | ❌ | ❌ | ❌ | -kiroxy will read and refresh tokens from the kiro-cli database directly. +kiroxy is purpose-built for Kiro IDE credentials. For multi-provider routing, use LiteLLM or OpenRouter. -**Option B β€” managed token vault** (recommended for multi-account): +
-Seed the vault with one or more accounts: +## Quick Start ```bash -# Single account -./kiroxy add-account --label=my-account --refresh-token= - -# Or bulk: line-delimited email:refresh_token:signature triplets -./kiroxy import-accounts --file=triplets.txt - -# Or pipe triplets: -cat triplets.txt | ./kiroxy import-accounts --stdin +# Pre-built binary (Linux/macOS, amd64/arm64) +VERSION=1.4.0 OS_ARCH=Darwin_arm64 +curl -sSL "https://github.com/nopperabbo/kiroxy/releases/download/v${VERSION}/kiroxy_${VERSION}_${OS_ARCH}.tar.gz" | tar xz +./kiroxy version ``` -The managed vault lives at `~/.kiroxy/tokens.db` (mode 0600). - -**About the triplet format:** `email:refresh_token:signature` β€” only the -refresh_token is sent upstream; the email is used as the account identifier -and the optional signature is stored in `metadata` for reference (kiroxy -never transmits it). - -Optional but recommended: - ```bash -export KIROXY_API_KEY="$(openssl rand -hex 32)" +# Or via Docker +docker pull ghcr.io/nopperabbo/kiroxy:latest +docker run --rm -p 127.0.0.1:8787:8787 -v kiroxy-data:/data ghcr.io/nopperabbo/kiroxy:latest ``` -### 4. Run - ```bash +# Configure & run +export KIROXY_KIRO_DB_PATH="$HOME/Library/Application Support/kiro-cli/data.sqlite3" ./kiroxy serve -# JSON log on stderr: -# {"time":"...","level":"INFO","msg":"kiroxy listening","version":"0.1.0-mvp","addr":"http://127.0.0.1:8787"} -``` - -### 5. First request - -Non-streaming: - -```bash -curl -sS http://127.0.0.1:8787/v1/messages \ - -H "X-Api-Key: $KIROXY_API_KEY" \ - -H "X-Claude-Code-Session-Id: $(uuidgen)" \ - -H "Content-Type: application/json" \ - -H "anthropic-version: 2023-06-01" \ - -d '{ - "model":"claude-sonnet-4-5", - "max_tokens":1024, - "messages":[{"role":"user","content":"Reply with just the word: kiroxy"}] - }' +# β†’ kiroxy listening on http://127.0.0.1:8787 ``` -Streaming: - ```bash -curl -sN http://127.0.0.1:8787/v1/messages \ - -H "X-Api-Key: $KIROXY_API_KEY" \ - -H "X-Claude-Code-Session-Id: $(uuidgen)" \ - -H "Content-Type: application/json" \ - -d '{ - "model":"claude-sonnet-4-5", - "max_tokens":1024, - "stream":true, - "messages":[{"role":"user","content":"Write a haiku about proxies."}] - }' -# Emits: event: message_start, content_block_delta ..., event: message_stop +# Connect any Anthropic-compatible client +export ANTHROPIC_BASE_URL=http://127.0.0.1:8787 +export ANTHROPIC_AUTH_TOKEN=$(openssl rand -hex 32) +claude # ← just works ``` -### 6. Use with Claude Code +
-```bash -export ANTHROPIC_BASE_URL=http://127.0.0.1:8787 -export ANTHROPIC_AUTH_TOKEN=$KIROXY_API_KEY # any non-empty value if KIROXY_API_KEY unset -claude -``` +## Dashboard ---- +The bundled **Mansion** dashboard ships in the same binary. Seven views, dark + light themes, mobile-responsive. + + + + + + + + + + +
+ Live stream +
Live Request Stream β€” Real-time SSE feed with drill-down +
+ Metrics +
Metrics β€” Time-series charts, SLO gauges +
+ Pool +
Account Pool β€” Density viz with anomaly emphasis +
+ Logs +
Logs β€” Volume histogram, facets, JSONL export +
+ +
+More screenshots +
+ + + + + +
+ Light theme +
Light Theme β€” WCAG AA contrast +
+ Mobile +
Mobile β€” All views adapt to 390px +
+
+ +
## Architecture -> **For the full component-by-component overview, see -> [docs/ARCHITECTURE.md](./docs/ARCHITECTURE.md).** Read it before -> modifying anything in `internal/`. The diagram below is the high-level -> sketch only. +> Full component-by-component overview: [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) ``` - KIROXY_API_KEY KIROXY_KIRO_DB_PATH - | (or vault) - v | - Claude Code /-+ +-------------------+ +--------------+ +------+ v - Cursor +->| /v1/messages |-->| reqconv |-->| kiro +--> Kiro IDE - OpenAI SDK | | /v1/messages/ | | (anthropic - | |client| (CodeWhisperer - your own curl /+ | count_tokens | | Kiro payload)| | | generateAssistant - | | +--------------+ +------+ Response) - | auth MW | ^ | - | log MW (ULID) | | | - | /healthz | | v - | /readyz | | +-------------+ - +----------+--------+ | | respconv | - | | | (Kiro SSE - | - v | | Anthropic | - +----------------+ | | SSE) | - | pool.TokenGetter| | +----+--------+ - | (LRU selection | | | - | + cooldowns) |-----------+ | - +----------+------+ v - | your client - v (streamed chunks) - +-----------------+ - | tokenvault | - | (SQLite + | - | gen-lock OAuth | - | refresh) | - +-----------------+ + Claude Code ─┐ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β” + Cursor β”œβ”€β”€β–Άβ”‚ /v1/messages │──▢│ reqconv │──▢│ kiro │──▢ Kiro IDE + any client β”€β”˜ β”‚ auth Β· log β”‚ β”‚ anthropicβ”‚ β”‚clientβ”‚ + β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β†’ kiro β”‚ β””β”€β”€β”€β”€β”€β”€β”˜ + β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ + β–Ό β–Ό + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β”‚ pool.Token β”‚ β”‚ respconv β”‚ + β”‚ (LRU+cool) β”‚ β”‚ kiro β†’ SSE β”‚ + β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ + β”‚ β”‚ + β–Ό β–Ό + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” your client + β”‚ tokenvault β”‚ (streamed chunks) + β”‚ SQLite+OAuthβ”‚ + β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` -Key patterns donated from: -- **d-kuro/kirocc** (Apache-2.0) β€” everything in `internal/{reqconv, respconv, kiroproto, kiroclient, anthropic, logging, httpx, tokencount, toolsearch, tracing, messages, models, testutil, auth}`. See `NOTICE`. -- **Quorinex/Kiro-Go** (MIT) β€” `internal/pool/pool.go` (adapted to LRU). -- **kadangkesel/hexos** (MIT) β€” `internal/tokenvault/vault.go` (ported from TypeScript, generation-lock pattern preserved). - ---- +
-## Environment variables +
+Environment Variables | Variable | Default | Purpose | -|---|---|---| -| `KIROXY_API_KEY` | (empty = open mode) | Required for clients; empty disables inbound auth (only safe on loopback) | -| `KIROXY_BIND` | `127.0.0.1` | Interface. Set `0.0.0.0` only behind a TLS reverse proxy | +|:---|:---|:---| +| `KIROXY_API_KEY` | _(empty = open)_ | Client auth key | +| `KIROXY_BIND` | `127.0.0.1` | Bind interface | | `KIROXY_PORT` | `8787` | TCP port | -| `KIROXY_DB_PATH` | `~/.kiroxy/tokens.db` | Managed-vault SQLite path (mode 0600 enforced) | -| `KIROXY_KIRO_DB_PATH` | (empty) | If set, read creds from this kiro-cli SQLite DB instead of the managed vault | -| `KIROXY_KIRO_REGION` | `us-east-1` | AWS region for the upstream | -| `KIROXY_LOG_LEVEL` | `info` | `debug` / `info` / `warn` / `error` | -| `KIROXY_SHUTDOWN_TIMEOUT` | `30` | Seconds to wait for in-flight SSE to drain on SIGTERM | +| `KIROXY_DB_PATH` | `~/.kiroxy/tokens.db` | Vault SQLite path | +| `KIROXY_KIRO_DB_PATH` | _(empty)_ | Read creds from kiro-cli DB | +| `KIROXY_KIRO_REGION` | `us-east-1` | AWS region | +| `KIROXY_LOG_LEVEL` | `info` | Log level | +| `KIROXY_SHUTDOWN_TIMEOUT` | `30` | Drain timeout (seconds) | ---- +
-## Endpoints +
+API Endpoints | Method | Path | Auth | Purpose | -|---|---|---|---| -| GET | `/healthz` | bypass | Liveness JSON `{"status":"ok","version":...}` | -| GET | `/readyz` | required | Readiness JSON; 503 if vault/pool down | -| POST | `/v1/messages` | required | Anthropic Messages API (streaming + non-streaming) | -| POST | `/v1/messages/count_tokens` | required | tiktoken-based token count | -| GET | `/dashboard` | loopback bypass | 302 redirect to the canonical `/dashboard-mansion` | -| GET | `/dashboard-mansion` | loopback bypass | Canonical operator dashboard (Mansion) | -| GET | `/dashboard/api/state` | loopback bypass | Pool + request snapshot JSON (shared by all dashboard variants) | -| GET | `/_variants/` | loopback bypass | Archived dashboards: `brutal`, `paper`, `nord`, `neon`, `muji`, `linear-premium`, `dashboard-next`, `dashboard-legacy` | - -Pass API key as either `X-Api-Key: ` or `Authorization: Bearer `. - -Every response carries `X-Request-Id`; clients may set their own via the same header. - ---- - -## Dashboard - -kiroxy ships a single canonical dashboard plus an archive of historical -design variants. - -- **Canonical:** `GET /dashboard-mansion` β€” the "operator desk" UI. - Warm charcoal + aged-brass amber, JetBrains Mono for data density, - Linear-grade motion discipline (View Transitions, @starting-style - enters, amber focus ring). Built with Svelte 5 + Vite; the bundle is - embedded in the binary so a fresh clone works with `go build` alone. -- **Redirect:** `GET /dashboard` β€” 302s to `/dashboard-mansion` so - existing bookmarks and scripts keep working. -- **Archive:** `GET /_variants/` β€” eight historical variants - (`brutal`, `paper`, `nord`, `neon`, `muji`, `linear-premium`, - `dashboard-next`, `dashboard-legacy`) kept fully functional for - reference. Each one commits to one taste without blending; see - [`docs/VARIANTS.md`](./docs/VARIANTS.md) for the philosophy matrix. - -Auth behavior for all dashboard routes: loopback requests skip the -`KIROXY_API_KEY` check (personal-use UX). Non-loopback access still -requires the key via `X-Api-Key` or `Authorization: Bearer`. - ---- - -## Troubleshooting - -> **For the full diagnostics playbook, see -> [docs/TROUBLESHOOTING.md](./docs/TROUBLESHOOTING.md).** The sections -> below cover the handful of errors most operators hit first. - -### `POST /v1/messages -> 401 authentication_error` - -You haven't added an account yet. Either set `KIROXY_KIRO_DB_PATH` to your kiro-cli database, or wait for M9's `kiroxy add-account` subcommand. - -### `POST /v1/messages -> 401 missing_api_key` - -You set `KIROXY_API_KEY` on the server but didn't send `X-Api-Key` (or `Authorization: Bearer`) from the client. Either unset `KIROXY_API_KEY` on the server (safe only on loopback) or pass the key on every request. - -### SSE chunks arrive all at once +|:---|:---|:---|:---| +| `POST` | `/v1/messages` | βœ“ | Anthropic Messages API | +| `POST` | `/v1/messages/count_tokens` | βœ“ | Token count | +| `GET` | `/healthz` | β€” | Liveness probe | +| `GET` | `/readyz` | βœ“ | Readiness probe | +| `GET` | `/dashboard-mansion` | loopback | Operator dashboard | -A reverse proxy in front of kiroxy may be buffering. Disable proxy buffering: -- **nginx**: `proxy_buffering off;` -- **Caddy**: `reverse_proxy { flush_interval -1 }` -- **Cloudflare**: enable "Early Hints" on the route, or use a worker - -### `go build` fails with `encoding/json/v2: build constraints exclude all Go files` - -Missing `GOEXPERIMENT=jsonv2`. Use `make build` (which sets it for you) or `export GOEXPERIMENT=jsonv2`. - -### Running multiple kiroxy instances from the same vault - -Safe. `internal/tokenvault` uses generation-locked OAuth refresh (see M4 in `BUILD_LOG.md`). At most one successful upstream refresh per (provider, account) at any instant. - -### AWS suspended my Kiro account - -Multi-account pooling against consumer Builder IDs can trigger abuse detection. Personal use only; 1-3 accounts is fine, keep request cadence reasonable. - ---- +
-## Build and test +
+CLI Reference ```bash -make build # single binary at ./kiroxy -make test # go test ./... -make gate # build + vet + fmt + test \u2014 required before commits -make test-race # race-mode test run +kiroxy serve # Run the proxy +kiroxy add-account # Register via AWS Builder ID OAuth +kiroxy import-accounts # Bulk import from triplet file +kiroxy list-accounts # Show vault accounts +kiroxy remove-account # Delete an account +kiroxy status # Pool + request snapshot +kiroxy debug-refresh # Force token refresh +kiroxy healthcheck # Docker HEALTHCHECK probe +kiroxy opencode-config # Emit opencode.json snippet +kiroxy version # Print version ``` -Pins `GOEXPERIMENT=jsonv2` automatically. +
---- - -## CLI Reference - -All kiroxy functionality ships as a single binary. Top-level shortcuts -(`--version`, `-v`, `--help`, `-h`, `help`) work without a subcommand. -Subcommand `--help` prints per-command usage. - -| Subcommand | One-liner | -|---|---| -| `serve` (default) | Run the HTTP proxy. Respects all `KIROXY_*` env vars. | -| `add-account` | Register a new account via AWS Builder ID device-code OAuth. | -| `import-accounts` | Bulk-import accounts from a line-delimited triplet file (`email:refresh_token:signature`). | -| `import-accounts-json` | Import accounts from Desktop-flow JSON (the `tools/onboard/` sidecar emits this format). | -| `list-accounts` | Print the managed vault's accounts with status, last-used, strikes. | -| `remove-account ` | Delete an account from the vault. | -| `status` | Pool + request snapshot (mirrors the dashboard JSON state). | -| `debug-refresh ` | Force a refresh against the configured source; print outcome. Useful for diagnosing revoked tokens. | -| `healthcheck` | In-binary `/healthz` probe. Used by the Docker `HEALTHCHECK` directive. | -| `opencode-config` | Emit an `opencode.json` provider snippet (7 resolver-verified Claude model IDs). | -| `version` | Print the `-ldflags -X main.version` stamp. | -| `help [subcommand]` | Print top-level or per-subcommand usage. | - -Examples: +
+Docker ```bash -# First-time setup -kiroxy import-accounts-json --file tools/onboard/kiro_tokens.json -kiroxy list-accounts - -# Operational -kiroxy status # pool snapshot -kiroxy debug-refresh $(kiroxy list-accounts -ids | head -1) -kiroxy opencode-config -output opencode.snippet.json - -# Container-friendly -kiroxy healthcheck && echo ok +docker pull ghcr.io/nopperabbo/kiroxy:latest +docker run --rm \ + -p 127.0.0.1:8787:8787 \ + -v kiroxy-data:/data \ + --read-only --cap-drop=ALL \ + --security-opt=no-new-privileges:true \ + -e KIROXY_API_KEY="your-key" \ + ghcr.io/nopperabbo/kiroxy:latest ``` -For the full per-subcommand flag list: `kiroxy help `. - ---- +| Control | Setting | +|:---|:---| +| Base image | `gcr.io/distroless/static-debian12:nonroot` | +| User | `nonroot` (UID 65532) | +| Root FS | Read-only | +| Capabilities | All dropped | +| Healthcheck | In-binary `kiroxy healthcheck` | -## Run with Docker +
-A multi-stage `Dockerfile` (distroless, nonroot, ~30 MiB) and `docker-compose.yml` ship with the repo. The token vault lives in a named volume at `/data/tokens.db` so it survives container restarts. +
+Supply Chain Security -### Quick start +Releases are signed with [Sigstore cosign](https://docs.sigstore.dev/) and include SBOM (SPDX format). ```bash -cp .env.example .env # fill in KIROXY_API_KEY -make docker-compose-up # build + start in background -docker compose logs -f kiroxy # tail JSON logs -curl http://127.0.0.1:8787/healthz # {"status":"ok",...} +cosign verify-blob \ + --certificate kiroxy_1.4.0_Darwin_arm64.tar.gz.cert \ + --signature kiroxy_1.4.0_Darwin_arm64.tar.gz.sig \ + --certificate-identity-regexp "github.com/nopperabbo/kiroxy" \ + --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \ + kiroxy_1.4.0_Darwin_arm64.tar.gz ``` -Add an account (running container has the same CLI surface as the native binary): - -```bash -docker compose exec kiroxy kiroxy add-account \ - --label=my-account --refresh-token= -docker compose exec kiroxy kiroxy list-accounts -``` +
-### Manual `docker run` +
+Troubleshooting -```bash -make docker-build # tags kiroxy: + kiroxy:local -docker run --rm \ - -p 127.0.0.1:8787:8787 \ - -v kiroxy-data:/data \ - --read-only --cap-drop=ALL \ - --security-opt=no-new-privileges:true \ - --tmpfs /tmp:size=16m,mode=1777 \ - -e KIROXY_API_KEY="$KIROXY_API_KEY" \ - kiroxy:local -``` +> Full diagnostics: [`docs/TROUBLESHOOTING.md`](docs/TROUBLESHOOTING.md) -### Security posture inside the container +| Symptom | Fix | +|:---|:---| +| `401 authentication_error` | No account added. Set `KIROXY_KIRO_DB_PATH` or run `kiroxy add-account` | +| `401 missing_api_key` | Client missing `X-Api-Key` header | +| SSE chunks arrive all at once | Disable proxy buffering (`proxy_buffering off`) | +| `go build` fails with json/v2 | Missing `GOEXPERIMENT=jsonv2` β€” use `make build` | -| Control | Setting | -|---|---| -| Base image | `gcr.io/distroless/static-debian12:nonroot` (no shell, no package manager) | -| User | `nonroot` (UID 65532) | -| Root FS | read-only; only `/data` (vault) and `/tmp` (tmpfs) are writable | -| Capabilities | all dropped | -| Privilege escalation | `no-new-privileges:true` | -| Healthcheck | in-binary `kiroxy healthcheck` subcommand (no curl, no shell) | +
-### Gotchas +
-- **`KIROXY_BIND` inside the container is `0.0.0.0`** \u2014 the network namespace IS the boundary. Control host-side exposure via `docker run -p` / compose's `ports:` mapping (defaults to `127.0.0.1:8787`). -- **`docker compose down` keeps the volume**; `docker compose down -v` wipes it (including `tokens.db`). Back up the volume before running `-v`. -- **Image tags never use `:latest`**; set `IMAGE=foo:bar` on `make docker-build` if you want a custom tag. +## Contributing ---- +PRs welcome. See [`CONTRIBUTING.md`](CONTRIBUTING.md) for guidelines. -## Contributing +```bash +make gate # fmt + vet + build + test +make lint # golangci-lint (25+ linters) +make test-race # race detector +``` -kiroxy is personal-use software, but PRs that fix bugs, add tests, or -improve docs are welcome. - -- **CI.** The repository ships a [GitHub Actions workflow](./.github/workflows/ci.yml) - that runs `make gate` on Ubuntu + macOS on every PR. A separate - [govulncheck workflow](./.github/workflows/vuln.yml) runs daily. -- **Pre-commit.** Run `make gate` locally before pushing. Set - `KIROXY_CI_STRICT=1` to also require `govulncheck`. -- **Releases.** Tag-triggered via the [release workflow](./.github/workflows/release.yml). - Local dry-run: `make release-dry-run` (requires goreleaser). -- **Commit style.** Conventional commits (`feat:`, `fix:`, `docs:`, - `ci:`, `build:`, `chore:`). The goreleaser changelog groups by prefix. -- **Anti-scope-creep.** New features land in `BACKLOG.md` first. Core - proxy path stays small. +
---- +## License -## Licensing and attribution +[MIT](LICENSE) -- **kiroxy** itself is MIT (see `LICENSE`). -- **NOTICE** enumerates donor projects, pinned commit SHAs, and per-donor licenses. -- Every ported file carries a header comment citing its origin. -- Personal, non-distributed use: AGPL contamination from any reference-only material (not present in this repo) does not attach. +
--- -## Links - -- **Research**: `../research/` β€” 170 KB of repo evaluations, comparison tables, extraction cookbook, recommendation. -- **Build plan**: `../BUILD_PLAN.md` β€” the milestone decomposition. -- **Build log**: `./BUILD_LOG.md` β€” append-only record of each milestone's gate. -- **Backlog**: `./BACKLOG.md` β€” Phase 2 and hygiene items. +
+ Built with care by @nopperabbo +
+ + πŸ’› Sponsor Β· + Report Bug Β· + Discuss + +

+ + Repobeats analytics + +
diff --git a/web/landing/public/social-preview.png b/web/landing/public/social-preview.png new file mode 100644 index 0000000..89dce1a Binary files /dev/null and b/web/landing/public/social-preview.png differ diff --git a/web/landing/src/components/Layout.astro b/web/landing/src/components/Layout.astro index 1a44589..17a8e7e 100644 --- a/web/landing/src/components/Layout.astro +++ b/web/landing/src/components/Layout.astro @@ -34,12 +34,17 @@ import '../styles/base.css'; + - + + + + +