{
  "markdown": "[![CI](https://github.com/ImperialBower/pkdealer/actions/workflows/CI.yaml/badge.svg)](https://github.com/ImperialBower/pkdealer/actions/workflows/CI.yaml)\n[![Workspace Check](https://github.com/ImperialBower/pkdealer/actions/workflows/workspace-check.yaml/badge.svg)](https://github.com/ImperialBower/pkdealer/actions/workflows/workspace-check.yaml)\n[![Security Audit](https://github.com/ImperialBower/pkdealer/actions/workflows/audit.yml/badge.svg)](https://github.com/ImperialBower/pkdealer/actions/workflows/audit.yml)\n[![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg)](CODE_OF_CONDUCT.md)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE-MIT)\n[![License: Apache 2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](LICENSE-APACHE)\n\n---\n\n# PKDealer — gRPC Poker Dealer Service\n\nPKDealer is a Rust workspace providing a gRPC poker dealer service, a matching gRPC client,\nshared Protobuf definitions, and a family of bot agents. The service manages a poker table:\nseating players, dealing hands, processing actions (bet / call / raise / fold), advancing\nstreets, and resolving showdowns.\n\nAgents connect over gRPC and play autonomously — rule-based archetypes from `pkcore`, a random\nbaseline, and live LLM players backed by Claude or a local Ollama model. The **arena** scripts\ncompose ad-hoc tables from these agents and bring up a full OpenTelemetry observability stack\n(collector + Jaeger + Prometheus + Grafana) alongside the dealer. A browser spectator lives in\nthe separate [`pkspectator`](https://github.com/ImperialBower/pkspectator) repo.\n\n---\n\n## Table of Contents\n\n- [Repository Structure](#repository-structure)\n- [Prerequisites](#prerequisites)\n- [Getting Started](#getting-started)\n- [Building](#building)\n- [Running](#running)\n- [Agents and the Arena](#agents-and-the-arena)\n- [Observability](#observability)\n- [Testing](#testing)\n- [Development Workflow](#development-workflow)\n- [Make Targets Reference](#make-targets-reference)\n- [Configuration](#configuration)\n- [CI and Workflows](#ci-and-workflows)\n- [Contributing](#contributing)\n- [License](#license)\n\n---\n\n## Repository Structure\n\n```\npkdealer/\n├── Cargo.toml               # Workspace root (9 member crates)\n├── Makefile                 # Developer convenience targets\n├── deny.toml                # cargo-deny configuration\n├── arena.toml               # Player registry for ./bin/arena (name → agent type)\n├── docker-compose.yml       # Dealer + agents + OTel collector + Jaeger + Prometheus + Grafana\n├── bin/                     # Launcher scripts (arena, aiarena, botarena, …)\n├── ops/                     # Observability stack config (collector, Grafana, Prometheus)\n├── proto/                   # Protobuf workspace assets\n├── crates/\n│   ├── pkdealer_proto/      # Shared Protobuf definitions + generated Rust types\n│   │   ├── proto/dealer.proto\n│   │   ├── build.rs         # tonic-build code generation\n│   │   └── src/lib.rs\n│   ├── pkdealer_service/    # gRPC server binary (the dealer)\n│   ├── pkdealer_client/     # gRPC client binary\n│   ├── pkdealer_agent_core/    # Shared gRPC agent infrastructure\n│   ├── pkdealer_agent_random/  # Random baseline bot\n│   ├── pkdealer_agent_rules/   # Rule-based bot driven by a pkcore BotProfile\n│   ├── pkdealer_agent_llm/     # Shared LlmBackend trait + poker-prompt logic\n│   ├── pkdealer_agent_claude/  # Claude LLM agent\n│   └── pkdealer_agent_ollama/  # Ollama (local LLM) agent\n└── docs/                    # EPIC specs, notes, and presentations\n```\n\n### Crate Roles\n\n| Crate | Type | Purpose |\n|---|---|---|\n| `pkdealer_proto` | library | Protobuf schema (`dealer.proto`) + tonic-generated Rust types |\n| `pkdealer_service` | binary | gRPC server that implements `DealerService` (the dealer) |\n| `pkdealer_client` | binary | gRPC client that connects to the service |\n| `pkdealer_agent_core` | library | Shared gRPC agent plumbing used by every bot |\n| `pkdealer_agent_random` | binary | Random baseline bot agent |\n| `pkdealer_agent_rules` | binary | Rule-based bot driven by a `pkcore` `BotProfile` archetype |\n| `pkdealer_agent_llm` | library | Shared `LlmBackend` trait + poker-prompt logic for LLM agents |\n| `pkdealer_agent_claude` | binary | Claude-backed LLM agent (OTel `gen_ai` instrumented) |\n| `pkdealer_agent_ollama` | binary | Ollama-backed local-LLM agent (OTel `gen_ai` instrumented) |\n\nThe browser spectator lives in a separate repo: [`pkspectator`](https://github.com/ImperialBower/pkspectator).\n\n---\n\n## Prerequisites\n\n| Tool | Version | Install |\n|---|---|---|\n| Rust toolchain | ≥ 1.85 (edition 2024) | `rustup update stable` |\n| Rust nightly | for `cargo-udeps` only | `rustup toolchain install nightly` |\n| `cargo-deny` | latest | `cargo install cargo-deny` |\n| `cargo-udeps` | latest | `cargo install cargo-udeps` |\n| `cargo-watch` | optional | `cargo install cargo-watch` |\n| GNU make | any | pre-installed on Linux; `brew install make` on macOS |\n\n> **macOS note:** the system `make` is BSD make. If you hit GNU-specific errors use `gmake`\n> (installed by `brew install make`).\n\nInstall all optional cargo tools at once:\n\n```sh\nmake install-tools\n```\n\n---\n\n## Getting Started\n\n```sh\ngit clone https://github.com/ImperialBower/pkdealer.git\ncd pkdealer\n\n# Build the entire workspace\ncargo build --workspace\n\n# Or use the Makefile shortcut\nmake build\n```\n\n---\n\n## Building\n\n```sh\n# Debug build (all crates, all features)\ncargo build --workspace --all-features\n\n# Release build\ncargo build --workspace --all-features --release\n\n# Single crate\ncargo build -p pkdealer_service\ncargo build -p pkdealer_client\ncargo build -p pkdealer_proto\n\n# Makefile shortcuts\nmake build          # debug\nmake build-release  # release\n```\n\nThe `pkdealer_proto` build script (`build.rs`) uses `protoc-bin-vendored` to compile\n`proto/dealer.proto` — no separate `protoc` installation is required.\n\n---\n\n## Running\n\n### Service\n\n```sh\n# Debug binary\ncargo run -p pkdealer_service\n\n# Release binary\ncargo run -p pkdealer_service --release\n\n# Custom bind address (default: 127.0.0.1:50051)\nPKDEALER_ADDR=0.0.0.0:9090 cargo run -p pkdealer_service\n```\n\n### Client\n\n```sh\n# Connect to the default address and send a ping\ncargo run -p pkdealer_client\n\n# Override endpoint or client-id via environment variables\nPKDEALER_ENDPOINT=http://127.0.0.1:9090 \\\nPKDEALER_CLIENT_ID=my-client \\\ncargo run -p pkdealer_client\n```\n\n---\n\n## Agents and the Arena\n\nBot agents are standalone gRPC clients that seat themselves at the dealer and play\nautonomously. Three launcher scripts in `bin/` bring up a dealer plus a line-up of agents\nvia Docker Compose, from simplest to most flexible:\n\n| Script | Line-up | External deps | Notes |\n|---|---|---|---|\n| `./bin/botarena` | Full 9-handed ring of every `pkcore` rule archetype | none | Pure offline rule-bot shootout |\n| `./bin/aiarena` | Fixed 3 rule bots + 3 local LLMs | Ollama on the host | The full demo stack — see [DEMO.md](DEMO.md) |\n| `./bin/arena` | Any line-up you name | depends on agents chosen | Reads [`arena.toml`](arena.toml), generates a one-off compose override |\n\nThe **dynamic arena runner** composes ad-hoc tables from the registry in `arena.toml`,\nwhich maps short names to an agent type (`rules`, `ollama`, `claude`, `gemini`) and config:\n\n```sh\n# Two GTO bots, a loose-aggressive bot, and one llama\n./bin/arena gto gto lag llama\n\n# Colon multiplicity shorthand: three GTO bots + one Claude\n./bin/arena gto:3 claude\n\n# Makefile wrappers\nmake arena PLAYERS=\"gto lag llama\"\nmake arena-down            # force-tear-down ALL arena containers + volumes\n```\n\nLive LLM players need credentials in the calling shell: the `claude` agent requires\n`ANTHROPIC_API_KEY` (live, billed). Rule bots and Ollama agents run fully locally.\n\n---\n\n## Observability\n\nThe service is OpenTelemetry-instrumented. `docker compose up -d --build` brings up the\ndealer plus the full telemetry stack — OTel collector, Jaeger (traces), Prometheus (metrics),\nand Grafana (dashboards). Stack config lives in `ops/`. The LLM agents emit `gen_ai`\nspans so model calls are traceable end-to-end.\n\nSee [`crates/pkdealer_service/README.md`](crates/pkdealer_service/README.md) for environment\nvariables and the full quickstart. Toggle OTel off with `OTEL_SDK_DISABLED=true` when running\ntests or `cargo run` without a collector.\n\n```sh\nmake ddown                 # tear down the demo stack (docker compose down -v)\n```\n\n---\n\n## Testing\n\n```sh\n# All tests (unit + integration)\ncargo test --workspace --all-features\n\n# With printed output\ncargo test --workspace --all-features -- --nocapture\n\n# Doc tests only\ncargo test --doc\n\n# Single crate\ncargo test -p pkdealer_service --all-features\ncargo test -p pkdealer_client  --all-features\n\n# End-to-end ping test (starts the service binary automatically)\ncargo test -p pkdealer_service --test e2e_ping\n\n# Makefile shortcuts\nmake test\nmake test-verbose\nmake test-service\nmake test-client\n```\n\n---\n\n## Development Workflow\n\n### Quick compile check (no binary output)\n\n```sh\nmake check\n# or\ncargo check --workspace --all-features\n```\n\n### Linting\n\n```sh\n# Standard clippy\nmake clippy\n\n# Pedantic (same flags as CI)\nmake clippy-pedantic\n```\n\n### Formatting\n\n```sh\n# Format in place\nmake fmt\n\n# Check only (no changes written — used by CI)\nmake fmt-check\n```\n\n### Documentation\n\n```sh\n# Generate docs (no-deps, all features, private items)\nmake doc\n\n# Generate and open in browser\nmake doc-open\n```\n\n### Watch mode\n\nRequires `cargo-watch` (`make install-watch`):\n\n```sh\nmake watch\n```\n\n### Dependency tree\n\n```sh\nmake tree              # full tree\nmake tree-duplicates   # highlight duplicates\n```\n\n### Security audit\n\n```sh\nmake audit             # cargo-deny advisories check\n```\n\n### Unused dependency check (nightly)\n\n```sh\nmake unused-deps\n```\n\n---\n\n## Make Targets Reference\n\nRun `make help` to print a summary at any time.\n\n| Target | Description |\n|---|---|\n| `make build` | Debug build of the full workspace |\n| `make build-release` | Release build |\n| `make serve` | Build and start the dealer service |\n| `make ddown` | Tear down the demo stack (`docker compose down -v`) |\n| `make demo` | Run the 9-player client demo (service must be running) |\n| `make demo-audit [COUNT=N]` | Run demo + audit N times (default 1) |\n| `make arena [PLAYERS=\"gto lag llama\"]` | Launch an ad-hoc arena table (see `./bin/arena --help`) |\n| `make arena-down` | Force-tear-down ALL arena containers + volumes |\n| `make test` | Run all workspace tests |\n| `make test-verbose` | Tests with `--nocapture` |\n| `make test-service` | Tests for `pkdealer_service` only |\n| `make test-client` | Tests for `pkdealer_client` only |\n| `make check` | Fast compile check (no output) |\n| `make fmt` | Auto-format all code |\n| `make fmt-check` | Check formatting without modifying |\n| `make clippy` | Run clippy |\n| `make clippy-pedantic` | Run clippy with `-Dclippy::pedantic` |\n| `make doc` | Generate workspace docs |\n| `make doc-open` | Generate docs and open in browser |\n| `make clean` | Remove all build artifacts |\n| `make update` | `cargo update` |\n| `make tree` | Dependency tree |\n| `make tree-duplicates` | Highlight duplicate deps |\n| `make audit` | Security audit via `cargo-deny` |\n| `make unused-deps` | Unused dep check (nightly) |\n| `make ci-quick` | `fmt-check` + `check` + `test` |\n| `make ci-local` | Full local CI: `fmt-check clippy-pedantic test doc` |\n| `make ayce` | Full pipeline: `fmt build test clippy doc` |\n| `make install-tools` | Install `cargo-deny` and `cargo-udeps` |\n| `make watch` | Watch mode (requires `cargo-watch`) |\n\n---\n\n## Configuration\n\n### Service bind address\n\n| Variable | Default | Description |\n|---|---|---|\n| `PKDEALER_ADDR` | `127.0.0.1:50051` | Address the service listens on |\n\n### Client\n\n| Variable | Default | Description |\n|---|---|---|\n| `PKDEALER_ENDPOINT` | `http://127.0.0.1:50051` | Service endpoint the client connects to |\n| `PKDEALER_CLIENT_ID` | `pkdealer-client` | Client identifier sent in ping requests |\n\n---\n\n## CI and Workflows\n\n| Workflow | File | Trigger | What it does |\n|---|---|---|---|\n| CI | `CI.yaml` | push / PR | fmt-check, clippy-pedantic, test, doc |\n| Workspace Check | `workspace-check.yaml` | push / PR | `cargo-deny`, `cargo-udeps` |\n| Security Audit | `audit.yml` | schedule + push | `cargo audit` advisory scan |\n\n---\n\n## Contributing\n\nPlease read [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) before contributing. All contributions are\nexpected to follow the [Contributor Covenant](https://www.contributor-covenant.org/) v2.1.\n\n---\n\n## License\n\nLicensed under either of\n\n* Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or\n  <http://www.apache.org/licenses/LICENSE-2.0>)\n* MIT license ([LICENSE-MIT](LICENSE-MIT) or\n  <http://opensource.org/licenses/MIT>)\n\nat your option.\n\n### Contribution\n\nUnless you explicitly state otherwise, any contribution intentionally\nsubmitted for inclusion in the work by you, as defined in the Apache-2.0\nlicense, shall be dual licensed as above, without any additional terms or\nconditions.\n\n---\n\n## Rust Resources\n\n- [The Rust Programming Language](https://doc.rust-lang.org/book/)\n- [Cargo Guide](https://doc.crates.io/guide.html)\n- [Asynchronous Programming in Rust](https://rust-lang.github.io/async-book/)\n- [tonic gRPC for Rust](https://github.com/hyperium/tonic)\n- [prost Protobuf for Rust](https://github.com/tokio-rs/prost)\n- [Rust API Guidelines](https://rust-lang.github.io/api-guidelines/)\n",
  "bytes": 13484,
  "sha": "89115a93f3435ea2bd2b0d60b4424e85eba27b6675107712be50a46b802c83a0",
  "repo_slug": "imperialbower/pkdealer",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/okf_imperialbower_pkdealer_okf_index_md_35df79a8/readme"
}