{"id":45014066,"url":"https://github.com/kunobi-ninja/kache","last_synced_at":"2026-05-03T22:05:05.825Z","repository":{"id":339195947,"uuid":"1158705125","full_name":"kunobi-ninja/kache","owner":"kunobi-ninja","description":"Zero-copy, content-addressed Rust build cache. No copies, no wasted disk — just hardlinks locally and S3 for sharing.","archived":false,"fork":false,"pushed_at":"2026-02-24T14:49:55.000Z","size":192,"stargazers_count":1,"open_issues_count":2,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-24T19:14:55.537Z","etag":null,"topics":["build-cache","caching","ci","developer-tools","hardlinks","rust","s3","zero-copy"],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kunobi-ninja.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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-02-15T19:43:57.000Z","updated_at":"2026-02-24T14:45:18.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/kunobi-ninja/kache","commit_stats":null,"previous_names":["kunobi-ninja/kache"],"tags_count":16,"template":false,"template_full_name":null,"purl":"pkg:github/kunobi-ninja/kache","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kunobi-ninja%2Fkache","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kunobi-ninja%2Fkache/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kunobi-ninja%2Fkache/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kunobi-ninja%2Fkache/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kunobi-ninja","download_url":"https://codeload.github.com/kunobi-ninja/kache/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kunobi-ninja%2Fkache/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29951031,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-28T18:42:55.706Z","status":"ssl_error","status_checked_at":"2026-02-28T18:42:48.811Z","response_time":90,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["build-cache","caching","ci","developer-tools","hardlinks","rust","s3","zero-copy"],"created_at":"2026-02-19T00:28:59.158Z","updated_at":"2026-05-03T22:05:05.806Z","avatar_url":"https://github.com/kunobi-ninja.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# kache\n\n[![Release](https://img.shields.io/github/v/release/kunobi-ninja/kache?label=release\u0026sort=semver\u0026color=blue)](https://github.com/kunobi-ninja/kache/releases/latest)\n[![CI](https://github.com/kunobi-ninja/kache/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/kunobi-ninja/kache/actions/workflows/ci.yml)\n[![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)\n[![MSRV](https://img.shields.io/badge/MSRV-1.95-blue.svg)](Cargo.toml)\n\nZero-copy, content-addressed Rust build cache. No copies, no wasted disk — just hardlinks locally and S3 for sharing.\n\nA drop-in `RUSTC_WRAPPER` that caches Rust compilation artifacts. Cache keys are blake3 hashes of normalized rustc invocations; cache hits restore via hardlinks, and identical blobs are stored once and shared. Optional S3 sync (AWS, Ceph, MinIO, R2) shares the cache across machines.\n\nLocal caching and direct S3 sync are stable today.\n\n**SOON:** a remote planner that prefetches from workspace manifests, dependency history, and build intent — warming the right artifacts before rustc asks for them.\n\n![kache: cold build populates the store, then `cargo clean \u0026\u0026 cargo build` restores every artifact via hardlinks](assets/demo.gif)\n\n\u003e Cold compile populates kache's store, `cargo clean` wipes `target/`, and the second build pulls every artifact back via hardlinks. The recording is reproducible — see [`assets/demo/`](assets/demo/) for the Dockerfile and tape script.\n\n## Why local kache is fast\n\nkache is useful even before remote cache is configured:\n\n- Local hits are restored with hardlinks into `target/`, so artifact bytes are not copied.\n- The store is content-addressed by blake3 hash, so identical artifact blobs are stored once and linked many times.\n- Misses compile normally, then kache records the outputs for future builds.\n- The daemon is optional for local caching. If it is not running, local hits and misses still work; remote checks, uploads, and prefetching degrade gracefully.\n- Incremental compilation is disabled while kache wraps rustc, because artifact caching replaces that path and avoids APFS-related corruption on macOS.\n\n## Screenshots\n\n`kache monitor` — live cache dashboard (Build / Projects / Store / Transfer tabs):\n\n![kache monitor TUI cycling through tabs against a populated cache](assets/monitor.gif)\n\n`kache clean` — find target/ dirs and see what's already in the kache store:\n\n![kache clean TUI listing target/ dirs with cached percentages](assets/clean.gif)\n\n## Install\n\n```sh\n# mise (recommended)\nmise use -g github:kunobi-ninja/kache@latest\n\n# cargo-binstall (downloads pre-built binary)\ncargo binstall kache\n\n# cargo (build from source)\ncargo install --git https://github.com/kunobi-ninja/kache\n```\n\n## Quick start\n\n```sh\n# Interactive setup: configures ~/.cargo/config.toml, installs the\n# background daemon as a login service, and starts it.\nkache init\n\n# Or accept all defaults non-interactively:\nkache init -y\n\n# Verify with:\nkache doctor\n```\n\n`kache init` is idempotent — re-run it any time to repair configuration. If you prefer to configure things by hand, just export `RUSTC_WRAPPER=kache` or add it to `~/.cargo/config.toml` under `[build]`.\n\n## Use in CI\n\n[`kache-action`](https://github.com/kunobi-ninja/kache-action) installs kache, wires it as `RUSTC_WRAPPER`, and persists the cache between runs. Drop one line into your workflow:\n\n```yaml\n- uses: kunobi-ninja/kache-action@v1\n```\n\nThat uses GitHub Actions cache by default. For S3-backed caching shared across repos or runners, pass `s3-bucket` plus credentials — see the action's README for the full input list.\n\n## Development\n\n```sh\nmise install\njust\njust check\njust ci\n```\n\nThe repo uses `just` as its single task runner. `mise.toml` pins the local Rust baseline and the `just` binary, while the `Justfile` keeps `RUSTC_WRAPPER` empty so kache never tries to build itself through kache.\n\n## Commands\n\n| Command | Description |\n|---|---|\n| `kache` | Print help (bare invocation) |\n| `kache init [-y] [--no-service] [--check]` | Interactive setup: cargo wrapper + service install + daemon start |\n| `kache doctor [--fix [--purge-sccache]] [--verify]` | Diagnose setup; `--fix` migrates from sccache, `--verify` checks cache integrity |\n| `kache monitor [--since \u003cdur\u003e]` | Live TUI dashboard showing build events, cache stats, and project breakdown |\n| `kache stats [--since \u003cdur\u003e]` | Non-interactive cache stats summary |\n| `kache list [\u003ccrate\u003e] [--sort name\\|size\\|hits\\|age]` | List cached entries, or show details for a specific crate |\n| `kache why-miss \u003ccrate\u003e` | Explain why a specific crate missed the cache |\n| `kache report [--format text\\|json\\|markdown\\|github] [--since \u003cdur\u003e] [--output \u003cpath\u003e]` | Generate a detailed build report |\n| `kache sync [--pull] [--push] [--all] [--dry-run]` | Synchronize local cache with S3 remote (pull + push) |\n| `kache save-manifest [--namespace \u003cns\u003e]` | Save a build manifest for future prefetch warming |\n| `kache gc [--max-age \u003cdur\u003e]` | Garbage collect — LRU eviction or age-based cleanup |\n| `kache purge [--crate-name \u003cname\u003e]` | Wipe entire cache or entries for a specific crate |\n| `kache clean [--dry-run]` | Find and delete `target/` directories with cache breakdown |\n| `kache config` | Open the TUI configuration editor |\n| `kache daemon` | Show daemon and service status |\n| `kache daemon run` | Start the persistent background daemon (foreground) |\n| `kache daemon start` | Start daemon in background (returns immediately) |\n| `kache daemon stop` | Stop a running daemon |\n| `kache daemon restart` | Restart daemon (via launchd/systemd if installed, else manual) |\n| `kache daemon install` | Install daemon as a system service (launchd/systemd) |\n| `kache daemon uninstall` | Remove the daemon service |\n| `kache daemon log` | Stream daemon logs |\n\nDurations use human-friendly format: `7d`, `24h`, `30m`.\n\n## Remote cache and configuration\n\n`kache sync` can pull from and push to S3-compatible storage directly, without the daemon. Pulls are filtered by the current workspace's `Cargo.lock` by default. See [Sync](docs/kache-docs/remote-cache/sync.mdx) for the full command behavior and S3 layout.\n\nConfiguration is available through `kache config`, environment variables, or config files. Environment variables win over config files, and project-local `.kache.toml` files are supported. See [Configuration](docs/kache-docs/getting-started/configuration.mdx) for the full reference.\n\n## Architecture\n\n- **Wrapper**: `RUSTC_WRAPPER` intercepts rustc calls, computes blake3 cache keys, restores hits via hardlinks\n- **Daemon**: Background process handles async S3 uploads, remote checks, and prefetch. Auto-restarts when binary is updated\n- **Store**: SQLite index + content-addressed blobs under `{cache_dir}/store/`; cache hits hardlink those blobs into `target/`\n- **Cache keys**: Deterministic blake3 hash of rustc version, crate name, source, dependencies, and normalized flags — portable across machines\n\n## Remote service\n\n**SOON:** server-side kache is the next milestone. The deployment model, auth integration, and HA behavior are still hardening — treat the planner service and chart as a preview today.\n\nAn optional remote planner service lives in [`crates/kache-service`](crates/kache-service). It persists planner state in an embedded SurrealDB database, serves planner endpoints over HTTP, and safely returns `use_fallback` when the database has no matching candidates.\n\nUseful commands:\n\n```sh\njust build-service\njust image-service\njust image-service-release\ncargo run -p kache-service\nhelm upgrade --install kache-service ./charts/kache-service\n```\n\nThe chart in [`charts/kache-service`](charts/kache-service) is intentionally small: one `Deployment`, one `Service`, optional `PersistentVolumeClaim`, security defaults, health probes, optional `kunobi-auth` bearer-token wiring through an existing `Secret`, and optional `kunobi-ha` Lease-based leader election. It does not bundle ingress or cluster-level policy.\n\nBearer-token auth is enabled by pointing the chart at an existing secret. Clients must send the same token through `KACHE_PLANNER_TOKEN`.\n\n```yaml\nauth:\n  existingSecret: kache-planner-token\n  existingSecretKey: token\n```\n\nThe service stores its embedded planner database at `/var/lib/kache/planner.db` by default. The chart supports either ephemeral storage for preview/dev environments or a PVC for persisted state:\n\n```yaml\nplanner:\n  dbPath: /var/lib/kache/planner.db\n  persistence:\n    enabled: true\n    type: pvc\n    mountPath: /var/lib/kache\n    size: 10Gi\n```\n\nFor bootstrap/migration only, the service can still import a legacy JSON planner snapshot on startup via `KACHE_PLANNER_SEED_STATE_FILE`.\n\nFor highly available deployments, enable leader election and raise the replica count. Followers stay healthy but not ready until they acquire the Kubernetes Lease:\n\n```yaml\nreplicaCount: 2\nha:\n  enabled: true\n  leaseName: kache-service\n```\n\nWhen combining HA with PVC-backed planner state, use storage that can be mounted by all scheduled replicas, or keep `replicaCount: 1`.\n\n## Contributing\n\nBug reports, feature ideas, and pull requests are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) for the dev setup, coding conventions, and PR process. To report a security vulnerability privately, follow [SECURITY.md](SECURITY.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkunobi-ninja%2Fkache","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkunobi-ninja%2Fkache","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkunobi-ninja%2Fkache/lists"}