RuleStack

Configs

Stacks

Compare

Diff

RuleStack

Configs

Stacks

Compare

Diff

Read API

RuleStack

Configs

Stacks

Compare

Diff

Read API

Configs/kurikomi-labs/komi-store/diff

Two files, one repository

kurikomi-labs/komi-store ships 2 formats across 13 indexed files. The question worth asking is whether the second one says anything the first does not.

CompareAGENTS.md ↔ CLAUDE.md
A · AGENTS.md · 843 wordsB · CLAUDE.md · 1396 words
What each file covers, counted
DimensionSharedOnly in AOnly in BOverlap
Sections217136%
Commands45333%
Section tags32150%

What each file covers

Sections

2 shared · 17 only in A · 13 only in B
  • − AGENTS.md
  • − Project Overview
  • − Build & Run Commands
  • − Android debug build
  • − Desktop (run in dev mode)
  • − Full build check (both platforms)
  • − Lint (ktlint auto-formats on preBuild/compileKotlin* tasks automatically)
  • − Desktop installers
  • − State Management Pattern (every screen)
  • − Module Layout
  • − Convention Plugins (build-logic)
  • − Dependency Injection
  • − Key Cross-Cutting Concerns
  • − Coding Conventions
  • − Adding a New Feature
  • − Feature-Level Documentation
  • − Versions
  • + Komi Store
  • + Build
  • + Structure
  • + State pattern (every screen)
  • + DI
  • + Core repositories (`core/domain`)
  • + Tech
  • + Convention plugins (`build-logic/convention/`)
  • + Adding a feature
  • + Key configuration
  • + Active skills (apply on matching domain)
  • + Conventions
  • + Approach
  •   Architecture
  •   Navigation

Commands

4 shared · 5 only in A · 3 only in B
  • − ./gradlew ktlintFormat
  • − ./gradlew ktlintCheck
  • − ./gradlew :composeApp:packageDmg
  • − ./gradlew :composeApp:packageExe
  • − ./gradlew :composeApp:packageDeb
  • + ./gradlew :composeApp:packageExe :composeApp:packageMsi
  • + ./gradlew :composeApp:packageDmg :composeApp:packagePkg
  • + ./gradlew :composeApp:packageDeb :composeApp:packageRpm
  •   ./gradlew :composeApp:assembleDebug
  •   ./gradlew :composeApp:run
  •   ./gradlew build
  •   gradle/libs.versions.toml

Section tags

3 shared · 2 only in A · 1 only in B
  • − lint-format
  • − docs
  • + git-pr
  •   build
  •   code-style
  •   architecture

Line diff

+95 added−90 removed36 unchanged27.5% identical
kurikomi-labs/komi-store · AGENTS.md
@@ −1 @@
1# AGENTS.md
2 
3This file provides guidance to WARP (warp.dev) when working with code in this repository.
4 
5## Project Overview
6 
7Komi Store is a cross-platform app store for GitHub releases built with **Kotlin Multiplatform (KMP)** and **Compose Multiplatform**. It targets **Android** (min API 26, target 36) and **Desktop** (Windows, macOS, Linux via JVM).
8 
9Package: `zed.rainxch.githubstore`
10 
11## Build & Run Commands
12 
13```bash
14# Android debug build
15./gradlew :composeApp:assembleDebug
 
 
 
 
 
16 
17# Desktop (run in dev mode)
18./gradlew :composeApp:run
19 
20# Full build check (both platforms)
21./gradlew build
22 
23# Lint (ktlint auto-formats on preBuild/compileKotlin* tasks automatically)
24./gradlew ktlintFormat # manual format all modules
25./gradlew ktlintCheck # check without fixing
26 
27# Desktop installers
28./gradlew :composeApp:packageDmg # macOS
29./gradlew :composeApp:packageExe # Windows
30./gradlew :composeApp:packageDeb # Linux
 
31```
32 
33**Requirements:** JDK 21+ (Temurin recommended), Android SDK for Android builds.
34 
35**Setup:** Create a GitHub OAuth App and put `GITHUB_CLIENT_ID=<your_id>` in `local.properties` (root). Callback URL: `githubstore://callback`.
36 
37## Architecture
38 
39**Clean Architecture + MVVM** with strict layer separation:
40 
41- **Domain** — Repository interfaces, models, use cases. No framework dependencies.
42- **Data** — Repository implementations, Ktor API clients, Room DAOs, DTOs, mappers. Each feature's DI module lives in `data/di/SharedModule.kt`.
43- **Presentation** — ViewModels with `StateFlow`/`Channel`, Compose screens.
44 
45### State Management Pattern (every screen)
 
 
 
 
 
 
 
 
46 
47Every ViewModel follows the same State/Action/Event pattern:
48 
49- `State` — data class holding all UI state, exposed via `StateFlow`
50- `Action` — sealed interface for user input (clicks, refreshes)
51- `Event` — sealed interface for one-off effects (navigation, toasts), sent via `Channel.receiveAsFlow()`
52 
53### Module Layout
54 
55```text
56composeApp/ # App entry points, navigation, DI wiring
57 src/commonMain/ # Shared UI & wiring
58 src/androidMain/ # Android entry (MainActivity)
59 src/jvmMain/ # Desktop entry (DesktopApp.kt)
60core/
61 domain/ # Shared interfaces, models, use cases
62 data/ # Networking (Ktor), database (Room), DI, platform impls
63 presentation/ # Material 3 theming, reusable UI components, localized strings (13 languages)
64feature/<name>/
65 domain/ # Feature-specific interfaces & models
66 data/ # Feature-specific implementations & Koin DI module
67 presentation/ # Feature ViewModel + Compose screens
68build-logic/convention/ # Custom Gradle convention plugins
69```
70 
71Some features (favourites, starred, recently-viewed, tweaks) are **presentation-only** — they use core repositories directly and register ViewModels in `composeApp/.../di/ViewModelsModule.kt` instead of having a `data/di/` layer.
72 
73### Convention Plugins (build-logic)
74 
75| Plugin ID | Use For |
76| :--- | :--- |
77| `convention.kmp.library` | KMP shared library modules (domain, data) |
78| `convention.cmp.library` | Compose Multiplatform library modules |
79| `convention.cmp.feature` | Feature presentation modules (auto-adds Compose + Koin + core:presentation) |
80| `convention.cmp.application` | Main app module |
81| `convention.room` | Room database modules |
82| `convention.buildkonfig` | Build-time config (reads from local.properties) |
83 
84### Navigation
85 
86Type-safe navigation using `@Serializable` sealed interface `GithubStoreGraph` in `composeApp/.../navigation/GithubStoreGraph.kt`. Routes are wired in `AppNavigation.kt`. Parameterized routes: `DetailsScreen(repositoryId, owner, repo, isComingFromUpdate)`, `DeveloperProfileScreen(username)`.
87 
88### Dependency Injection
89 
90**Koin** — each feature's data layer defines a module in `data/di/SharedModule.kt`. All modules are registered in `composeApp/.../di/initKoin.kt`. ViewModels injected via `koinViewModel()`. `DetailsViewModel` and `MirrorPickerViewModel` use manual Koin `viewModel { }` with `parametersOf()` for constructor args; all others use `viewModelOf(::ClassName)`.
91 
92### Key Cross-Cutting Concerns
93 
94- **Auth flow:** GitHub device-flow OAuth. Primary path goes through backend proxy (`/v1/auth/device/start`, `/v1/auth/device/poll`); falls back to direct GitHub only on infrastructure errors (5xx, timeouts). HTTP 4xx and GitHub's negative 200-bodies never trigger fallback. Backend rate limits (10 starts/hr, 200 polls/hr per IP) are hard — do not add retry loops.
95- **`X-GitHub-Token` header:** Forwarded on every backend passthrough route — `/v1/search`, `/v1/search/explore`, `/v1/repo/{owner}/{name}`, `/v1/releases/{owner}/{name}`, `/v1/readme/{owner}/{name}`, `/v1/user/{username}`. Backend re-sends as `Authorization: token $token` so upstream GitHub calls run under the user's 5000/hr OAuth quota; without it the request falls back to the shared 60/hr anonymous bucket and a single 4xx can poison the backend's 15-min negative cache for everyone. DB-only routes (`/v1/categories`, `/v1/topics`, `/v1/events`, `/v1/auth/device/*`, `/v1/badge/*`) never get the header. Sourced via `BackendApiClient.currentUserGithubToken()` (`private`), never logged. 401 from passthrough routes ≠ session expired — `AuthenticationStateImpl` debounces consecutive 401s under the same token before clearing the session.
96- **Platform branching:** Source sets are `commonMain` (shared), `androidMain` (Android), `jvmMain` (Desktop). Some features (apps, installation, Shizuku) are Android-only.
97- **Shizuku (Android):** Optional silent install via AIDL service. Falls back to standard installer on failure.
98 
99## Coding Conventions
100 
101- Packages: `zed.rainxch.{module}.{layer}` (e.g. `zed.rainxch.home.data.repository`)
102- Private state: underscore prefix `_state`, `_events`
103- Sealed classes/interfaces for type-safe routes, actions, events
104- Repository pattern: interface in `domain/`, implementation in `data/`
105- Ktlint auto-runs on `preBuild`/`compileKotlin*` tasks; `ignoreFailures = true`
106- Ktlint rules: wildcard imports allowed, filename rule disabled, `@Composable` functions exempt from function naming rule (see `.editorconfig`)
 
 
 
 
 
 
 
107 
108## Adding a New Feature
109 
1101. Create `feature/<name>/domain/`, `feature/<name>/data/`, `feature/<name>/presentation/`
1112. Add `build.gradle.kts` in each using the appropriate convention plugin
1123. Add `include` entries in `settings.gradle.kts`
1134. Define domain interfaces/models in `domain/`
1145. Implement repository + Koin DI module in `data/di/SharedModule.kt`
1156. Create ViewModel (State/Action/Event pattern) and Screen in `presentation/`
1167. Add navigation route to `GithubStoreGraph.kt` and wire in `AppNavigation.kt`
1178. Register the Koin module in `initKoin.kt`
 
 
 
 
 
 
 
 
118 
119## Feature-Level Documentation
120 
121Each `feature/` directory contains its own `CLAUDE.md` with module structure, key interfaces, navigation routes, and implementation notes. Read those for feature-specific guidance.
 
 
 
 
 
 
122 
123## Versions
124 
125All library versions managed in `gradle/libs.versions.toml`. Key versions: Kotlin 2.3.10, Compose Multiplatform 1.10.3, Ktor 3.4.0, Room 2.8.4, Koin 4.1.1.
 
 
 
 
 
126 
kurikomi-labs/komi-store · CLAUDE.md
@@ +1 @@
1# Komi Store
2 
3Cross-platform app store for GitHub + Codeberg + Forgejo releases. **Kotlin Multiplatform** + **Compose Multiplatform**. Android (min API 26) + Desktop (JVM: Win/macOS/Linux). Package `zed.rainxch.githubstore`. Version 1.8.3 (code 18). Target SDK 36.
4 
5## Build
6 
 
 
 
 
 
 
7```bash
8./gradlew :composeApp:assembleDebug # Android
9./gradlew :composeApp:run # Desktop dev
10./gradlew :composeApp:packageExe :composeApp:packageMsi # Win installer
11./gradlew :composeApp:packageDmg :composeApp:packagePkg # macOS
12./gradlew :composeApp:packageDeb :composeApp:packageRpm # Linux
13./gradlew build # full
14```
15 
16JDK 21+. Android SDK for Android.
 
17 
18## Structure
 
19 
20```text
21composeApp/ # entry points, navigation, DI wiring (commonMain / androidMain / jvmMain)
22core/
23 domain/ # interfaces, models, use cases (no framework deps)
24 data/ # repos, Ktor, Room, Koin, platform impls
25 presentation/ # Material 3 theme + reusable components + 14-locale strings
26feature/
27 apps auth details dev-profile favourites homeP profile recently-viewed search starred tweaks
28build-logic/convention/ # convention plugins
29```
30 
31Each feature: up to 3 sub-modules (`domain/`, `data/`, `presentation/`). `favourites`, `starred`, `recently-viewed` are presentation-only.
32 
 
 
33## Architecture
34 
35Clean Architecture + MVVM. Layers: **Domain** (contracts), **Data** (Ktor + Room + Koin DI), **Presentation** (ViewModels with `StateFlow`/`Channel`, Compose).
36 
37### State pattern (every screen)
 
 
38 
39```kotlin
40class XViewModel : ViewModel() {
41 private val _state = MutableStateFlow(XState())
42 val state = _state.asStateFlow() // or .stateIn(WhileSubscribed)
43 private val _events = Channel<XEvent>()
44 val events = _events.receiveAsFlow()
45 fun onAction(action: XAction) { ... }
46}
47```
48 
49`State` = data class. `Action` = sealed (user input). `Event` = sealed (one-off effects).
50 
51### Navigation
 
 
52 
53`@Serializable` sealed interface `GithubStoreGraph` in `composeApp/.../app/navigation/`. Routes: `HomeScreen`, `SearchScreen`, `AuthenticationScreen`, `ProfileScreen`, `TweaksScreen`, `FavouritesScreen`, `StarredReposScreen`, `RecentlyViewedScreen`, `AppsScreen`, `OnboardingScreen`, `ExternalImportScreen`, `MirrorPickerScreen`, `StarredPickerScreen`, `SkippedUpdatesScreen`, `HiddenRepositoriesScreen`, `WhatsNewHistoryScreen`, `AnnouncementsScreen`, `HostTokensScreen`, `DetailsScreen(repositoryId, owner, repo, isComingFromUpdate, sourceHost)`, `DeveloperProfileScreen(username)`. `DetailsScreen.sourceHost` is non-null for Codeberg / Forgejo / custom-forge repos — routes all `DetailsRepository` calls through `ForgejoClientRegistry` instead of the GitHub-backed default path.
54 
55### DI
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56 
57Koin. Feature modules in `data/di/SharedModule.kt`. ViewModels in `composeApp/.../app/di/ViewModelsModule.kt` (`viewModelOf(::X)` or explicit `viewModel { ... }`). Wired in `initKoin.kt`.
58 
59## Core repositories (`core/domain`)
60 
61`FavouritesRepository`, `StarredRepository`, `InstalledAppsRepository`, `SeenReposRepository`, `HiddenReposRepository`, `SearchHistoryRepository`, `TweaksRepository`, `AuthenticationState`, `ThemesRepository`, `ProxyRepository`, `RateLimitRepository`, `ExternalImportRepository`, `TelemetryRepository`, `HostTokenRepository` (per-host PATs, KSafe-encrypted). Network: `ForgejoApiClient` + `ForgejoClientRegistry` (per-host Ktor clients, thread-safe via Mutex, proxy-aware, closes cached engines on shutdown / proxy change). Util: `AssetVariant` (token/glob/stem fingerprinting), `assetPlatformOf`, `RepoIdCodec` (23-bit host fingerprint + 40-bit raw id packed into the existing 64-bit `repoId` slot — sign bit = foreign source), `RepositoryUrlParser` (recognises GitHub + Codeberg + gitea.com + git.disroot.org + user-added forge hosts). System interfaces: `Installer`, `InstallerStatusProvider`, `PackageMonitor`, `SystemInstallSerializer`.
 
 
 
 
 
 
 
62 
63## Tech
64 
65Kotlin 2.3.10, Compose Multiplatform 1.10.3, Ktor 3.4.0, Room 2.8.4, Koin 4.1.1, kotlinx.serialization 1.10.0, DataStore 1.2.0, Landscapist 2.9.5, Kermit 2.0.8, MOKO Permissions 0.20.1, Navigation Compose 2.9.2, multiplatform-markdown-renderer 0.39.2, Shizuku 13.1.5, WorkManager 2.11.1, kotlinx.datetime 0.7.1. Versions in `gradle/libs.versions.toml`.
66 
67## Convention plugins (`build-logic/convention/`)
68 
69`convention.kmp.library` (domain/data), `convention.cmp.library` (core/presentation), `convention.cmp.feature` (feature presentation), `convention.cmp.application` (main app), `convention.room`, `convention.buildkonfig`.
70 
71## Adding a feature
72 
731. `feature/<name>/{domain,data,presentation}/` with appropriate convention plugin
742. `include` in `settings.gradle.kts`
753. Domain interfaces → impl + Koin module in `data/di/SharedModule.kt` → ViewModel + Screen
764. Route in `GithubStoreGraph.kt` + wire in `AppNavigation.kt` + register Koin in `initKoin.kt`
77 
78## Key configuration
79 
80- **GitHub OAuth:** `GITHUB_CLIENT_ID` in `local.properties`. Deep links: `githubstore://auth` (web-OAuth handoff), `githubstore://callback` (legacy device-flow leftover), `githubstore://repo`, `githubstore://apps`.
81- **Shizuku (Android):** silent install via `ShizukuProvider` → AIDL → `pm install -S`. Fallback to standard installer on failure.
82- **Desktop logs:** `CrashReporter` (first line of `DesktopApp.main`) tees stdout/stderr to rotating `session.log` + writes `crash-<ts>.log` on uncaught. Paths: `~/Library/Logs/GitHub-Store/` (macOS), `%LOCALAPPDATA%/GitHub-Store/logs/` (Win), `$XDG_STATE_HOME/GitHub-Store/logs/` (Linux). Android = Logcat.
83- **macOS distribution:** Homebrew cask in tap `openhub-store/tap` (separate repo `homebrew-tap`). `brew install --cask github-store`. Unsigned at present — user must `xattr -dr com.apple.quarantine /Applications/GitHub-Store.app` after install. CI builds `.dmg` + `.pkg` on every push to `generate-installers`; tap cask updates automatically on release.
84- **`X-GitHub-Token` header:** Client attaches when `TokenStore.currentToken()` is non-null on `/v1/search`, `/v1/search/explore`, `/v1/repo`, `/v1/releases`, `/v1/readme`, `/v1/user`. Backend re-sends as `Authorization: token $token` to GitHub. Without it, backend round-robins a 4-token service pool. Upstream 401 remapped to backend `502` (handled like "GitHub unreachable" — fall back via `shouldFallbackToGithubOrRethrow`). `429` = no fallback (same wall), only backoff. `UnauthorizedInterceptor` only on direct-GitHub client; `AuthenticationStateImpl` debounces consecutive 401s by token snapshot.
85- **Auth flow (web-OAuth-first):** Primary path is web OAuth with PKCE + handoff. `feature/auth/data/crypto/PkceGenerator` mints `(state, codeVerifier, codeChallenge)`; `WebAuthApi.register` POSTs verifier + challenge + state to `https://github-store.org/auth/register` (Cloudflare Worker stashes them in Workers KV) and returns `authUrl`. User opens it, authorizes on `github.com`, GitHub redirects to `github-store.org/auth/callback?code&state` where the Worker exchanges the code via `api.github-store.org` (backend stores `(handoffId → access_token)` for 60s in Postgres with atomic `DELETE…RETURNING`), then bounces back to `githubstore://auth?h=<handoffId>`. App reads handoff via `WebAuthApi.consumeHandoff` (GETDEL semantics). Secondary path: device flow via backend `/v1/auth/device/start` + `/poll`, `AuthPath` (`Backend`|`Direct`) tracked in `SavedStateHandle`, only escalates `Backend → Direct` on infra errors. Tertiary: paste a Personal Access Token (`signInWithPat` — validates against `/user`, persists optimistically when GitHub unreachable). Backend rate limits: 10 device-starts/hr, 200 device-polls/hr per IP. Endpoints in `core/data/network/BackendEndpoints.kt` (`BACKEND_ORIGIN`, `WEB_ORIGIN`).
86- **Windows installer signing (SignPath Foundation):** CI workflow `.github/workflows/build-desktop-platforms.yml` job `sign-windows` after every push to `generate-installers` branch. Action pinned to commit SHA (not `@v2`). Secrets: `SIGNPATH_API_TOKEN`, `SIGNPATH_ORGANIZATION_ID` (`1ecf111e-...`). Variable `SIGNPATH_SIGNING_POLICY_SLUG` = `test-signing` until prod cert issued; flip to `release-signing`. Project slug `GitHub-Store`, artifact config slug `initial`. Unsigned artifact deleted post-sign; only `windows-installers-signed` reaches the draft release.
87- **WinGet publish:** `.github/workflows/winget-publish.yml` fires on `release: [released]`. Action `vedantmgoyal9/winget-releaser@main`. Secret `WINGET_TOKEN` = PAT with `Contents+Pull requests: write` on `OpenHub-Store/winget-pkgs` (fork of `microsoft/winget-pkgs`). Pin `fork-user: OpenHub-Store` explicitly so the action doesn't infer from token owner.
88- **Forges (Codeberg / Forgejo / Gitea):** `ForgejoApiClient` per host (60s req / 30s connect+socket timeouts, exponential retry on 5xx + IOException). `ForgejoClientRegistry.clientFor(host)` cached + Mutex-guarded. Direct-to-forge — no backend mediator. `RepoIdCodec` packs host fingerprint into `repoId` so the existing GitHub-shaped schema survives. README via `/contents/README.md?ref={branch}` (Forgejo has NO `/readme` endpoint). License sniffed from `/contents/LICENSE` regex against SPDX headers. Downloads aggregated by summing `asset.download_count` across releases.
89- **Per-host PATs:** `HostTokenRepository` stores `{host, token, label, createdAt}` rows AES-256-GCM encrypted via KSafe. `HostTokenInterceptor` (Ktor plugin) injects `Authorization: token $pat` on matched host. `HostNames.apiHostToTokenHost` maps `api.github.com → github.com` so the GitHub-direct client looks up the right PAT. UI at `Tweaks → Access Tokens` (`HostTokensScreen`).
90- **KSafe:** AES-256-GCM with hardware-backed Keystore on Android. Wraps every persisted credential / pref via `core/data/secure/KSafeSafe.kt` extension funcs (`safeGet`, `safePut`, `safeDelete`, `safeGetFlow`) — surface log + return null/false on transient failure instead of throwing through coroutine scopes.
91- **Translation providers:** `TranslationProvider` enum = `GOOGLE`, `YOUDAO`, `LIBRE_TRANSLATE`, `DEEPL`, `MICROSOFT`. Each per-provider config persisted via `TweaksRepository` (KSafe-encrypted). `TranslationRepositoryImpl.resolveTranslator()` picks the impl. LibreTranslate defaults to the bundled `translate.disroot.org` mirror when user URL pref blank. DeepL auto-routes `:fx`-suffixed keys to `api-free.deepl.com`. Microsoft uses No-Trace by default — text never stored, never used for training.
92- **Gradle:** Config + build cache enabled. 4GB Gradle heap, 3GB Kotlin daemon. Official Kotlin style.
93 
94## Active skills (apply on matching domain)
95 
96- **caveman** — session default, terse output.
97- **karpathy-guidelines** — anti-overcomplication, minimal diffs, surface assumptions, verifiable success criteria. Every coding task.
98- **one-skill-to-rule-them-all** — watch for skill-capture opportunities during multi-step work.
99- **gsd-inbox** - Triage open GitHub issues + PRs against templates. Our exact pattern — automate the "check issue #N, draft reply, ship fix" loop.
100- **gsd-ship** - Create PR + review + prep for merge. Every task ends here.
101- **gsd-quick** - Trivial task with atomic commits + state tracking. Matches our small-commit policy.
102- **gsd-debug** - Systematic debugging with persistent state across context resets. For bug-hunt cycles.
103- **android-* skills** (`~/.claude/skills/android/`) — auto-fire by description match; apply when in matching domain:
104 - `android-compose-ui` — composables, recomposition, animations, modifiers, design system
105 - `android-data-layer` — repos, DTOs, Room, Ktor, mappers
106 - `android-di-koin` — Koin module setup, ViewModel injection
107 - `android-error-handling` — Result wrapper, typed errors
108 - `android-module-structure` — feature-layered modules, convention plugins
109 - `android-navigation` — type-safe Compose nav
110 - `android-presentation-mvi` — State/Action/Event, Root/Screen split, UiText, SavedStateHandle
111 - `android-testing` — testing patterns
112 
113## Conventions
114 
115- Packages `zed.rainxch.{module}.{layer}`
116- Private state fields prefix `_state`
117- Sealed routes/actions/events
118- Repository pattern: interface in `domain/`, impl in `data/`
119- Source sets: `commonMain` shared, `androidMain`, `jvmMain`
120- **No KDoc, no inline comments** unless the user explicitly asks. No function/class docs. Inline only for non-obvious invariants, tricky concurrency, workarounds. Applies globally.
121- Feature-specific guidance in each `feature/*/CLAUDE.md`
122 
123## Approach
124 
125- Read existing files before writing. Don't re-read unless changed.
126- Thorough in reasoning, concise in output.
127- Skip files over 100KB unless required.
128- No sycophantic openers or closing fluff.
129- No emojis or em-dashes.
130- Do not guess APIs, versions, flags, commit SHAs, or package names. Verify by reading code or docs before asserting, researching if necessary.
131 
@@ −1 +1 @@
1−# AGENTS.md
1+# Komi Store
22  
3−This file provides guidance to WARP (warp.dev) when working with code in this repository.
3+Cross-platform app store for GitHub + Codeberg + Forgejo releases. **Kotlin Multiplatform** + **Compose Multiplatform**. Android (min API 26) + Desktop (JVM: Win/macOS/Linux). Package `zed.rainxch.githubstore`. Version 1.8.3 (code 18). Target SDK 36.
44  
5−## Project Overview
5+## Build
66  
7−Komi Store is a cross-platform app store for GitHub releases built with **Kotlin Multiplatform (KMP)** and **Compose Multiplatform**. It targets **Android** (min API 26, target 36) and **Desktop** (Windows, macOS, Linux via JVM).
8− 
9−Package: `zed.rainxch.githubstore`
10− 
11−## Build & Run Commands
12− 
137 ```bash
14−# Android debug build
15−./gradlew :composeApp:assembleDebug
8+./gradlew :composeApp:assembleDebug # Android
9+./gradlew :composeApp:run # Desktop dev
10+./gradlew :composeApp:packageExe :composeApp:packageMsi # Win installer
11+./gradlew :composeApp:packageDmg :composeApp:packagePkg # macOS
12+./gradlew :composeApp:packageDeb :composeApp:packageRpm # Linux
13+./gradlew build # full
14+```
1615  
17−# Desktop (run in dev mode)
18−./gradlew :composeApp:run
16+JDK 21+. Android SDK for Android.
1917  
20−# Full build check (both platforms)
21−./gradlew build
18+## Structure
2219  
23−# Lint (ktlint auto-formats on preBuild/compileKotlin* tasks automatically)
24−./gradlew ktlintFormat # manual format all modules
25−./gradlew ktlintCheck # check without fixing
26− 
27−# Desktop installers
28−./gradlew :composeApp:packageDmg # macOS
29−./gradlew :composeApp:packageExe # Windows
30−./gradlew :composeApp:packageDeb # Linux
20+```text
21+composeApp/ # entry points, navigation, DI wiring (commonMain / androidMain / jvmMain)
22+core/
23+ domain/ # interfaces, models, use cases (no framework deps)
24+ data/ # repos, Ktor, Room, Koin, platform impls
25+ presentation/ # Material 3 theme + reusable components + 14-locale strings
26+feature/
27+ apps auth details dev-profile favourites homeP profile recently-viewed search starred tweaks
28+build-logic/convention/ # convention plugins
3129 ```
3230  
33−**Requirements:** JDK 21+ (Temurin recommended), Android SDK for Android builds.
31+Each feature: up to 3 sub-modules (`domain/`, `data/`, `presentation/`). `favourites`, `starred`, `recently-viewed` are presentation-only.
3432  
35−**Setup:** Create a GitHub OAuth App and put `GITHUB_CLIENT_ID=<your_id>` in `local.properties` (root). Callback URL: `githubstore://callback`.
36− 
3733 ## Architecture
3834  
39−**Clean Architecture + MVVM** with strict layer separation:
35+Clean Architecture + MVVM. Layers: **Domain** (contracts), **Data** (Ktor + Room + Koin DI), **Presentation** (ViewModels with `StateFlow`/`Channel`, Compose).
4036  
41−- **Domain** — Repository interfaces, models, use cases. No framework dependencies.
42−- **Data** — Repository implementations, Ktor API clients, Room DAOs, DTOs, mappers. Each feature's DI module lives in `data/di/SharedModule.kt`.
43−- **Presentation** — ViewModels with `StateFlow`/`Channel`, Compose screens.
37+### State pattern (every screen)
4438  
45−### State Management Pattern (every screen)
39+```kotlin
40+class XViewModel : ViewModel() {
41+ private val _state = MutableStateFlow(XState())
42+ val state = _state.asStateFlow() // or .stateIn(WhileSubscribed)
43+ private val _events = Channel<XEvent>()
44+ val events = _events.receiveAsFlow()
45+ fun onAction(action: XAction) { ... }
46+}
47+```
4648  
47−Every ViewModel follows the same State/Action/Event pattern:
49+`State` = data class. `Action` = sealed (user input). `Event` = sealed (one-off effects).
4850  
49−- `State` — data class holding all UI state, exposed via `StateFlow`
50−- `Action` — sealed interface for user input (clicks, refreshes)
51−- `Event` — sealed interface for one-off effects (navigation, toasts), sent via `Channel.receiveAsFlow()`
51+### Navigation
5252  
53−### Module Layout
53+`@Serializable` sealed interface `GithubStoreGraph` in `composeApp/.../app/navigation/`. Routes: `HomeScreen`, `SearchScreen`, `AuthenticationScreen`, `ProfileScreen`, `TweaksScreen`, `FavouritesScreen`, `StarredReposScreen`, `RecentlyViewedScreen`, `AppsScreen`, `OnboardingScreen`, `ExternalImportScreen`, `MirrorPickerScreen`, `StarredPickerScreen`, `SkippedUpdatesScreen`, `HiddenRepositoriesScreen`, `WhatsNewHistoryScreen`, `AnnouncementsScreen`, `HostTokensScreen`, `DetailsScreen(repositoryId, owner, repo, isComingFromUpdate, sourceHost)`, `DeveloperProfileScreen(username)`. `DetailsScreen.sourceHost` is non-null for Codeberg / Forgejo / custom-forge repos — routes all `DetailsRepository` calls through `ForgejoClientRegistry` instead of the GitHub-backed default path.
5454  
55−```text
56−composeApp/ # App entry points, navigation, DI wiring
57− src/commonMain/ # Shared UI & wiring
58− src/androidMain/ # Android entry (MainActivity)
59− src/jvmMain/ # Desktop entry (DesktopApp.kt)
60−core/
61− domain/ # Shared interfaces, models, use cases
62− data/ # Networking (Ktor), database (Room), DI, platform impls
63− presentation/ # Material 3 theming, reusable UI components, localized strings (13 languages)
64−feature/<name>/
65− domain/ # Feature-specific interfaces & models
66− data/ # Feature-specific implementations & Koin DI module
67− presentation/ # Feature ViewModel + Compose screens
68−build-logic/convention/ # Custom Gradle convention plugins
69−```
55+### DI
7056  
71−Some features (favourites, starred, recently-viewed, tweaks) are **presentation-only** — they use core repositories directly and register ViewModels in `composeApp/.../di/ViewModelsModule.kt` instead of having a `data/di/` layer.
57+Koin. Feature modules in `data/di/SharedModule.kt`. ViewModels in `composeApp/.../app/di/ViewModelsModule.kt` (`viewModelOf(::X)` or explicit `viewModel { ... }`). Wired in `initKoin.kt`.
7258  
73−### Convention Plugins (build-logic)
59+## Core repositories (`core/domain`)
7460  
75−| Plugin ID | Use For |
76−| :--- | :--- |
77−| `convention.kmp.library` | KMP shared library modules (domain, data) |
78−| `convention.cmp.library` | Compose Multiplatform library modules |
79−| `convention.cmp.feature` | Feature presentation modules (auto-adds Compose + Koin + core:presentation) |
80−| `convention.cmp.application` | Main app module |
81−| `convention.room` | Room database modules |
82−| `convention.buildkonfig` | Build-time config (reads from local.properties) |
61+`FavouritesRepository`, `StarredRepository`, `InstalledAppsRepository`, `SeenReposRepository`, `HiddenReposRepository`, `SearchHistoryRepository`, `TweaksRepository`, `AuthenticationState`, `ThemesRepository`, `ProxyRepository`, `RateLimitRepository`, `ExternalImportRepository`, `TelemetryRepository`, `HostTokenRepository` (per-host PATs, KSafe-encrypted). Network: `ForgejoApiClient` + `ForgejoClientRegistry` (per-host Ktor clients, thread-safe via Mutex, proxy-aware, closes cached engines on shutdown / proxy change). Util: `AssetVariant` (token/glob/stem fingerprinting), `assetPlatformOf`, `RepoIdCodec` (23-bit host fingerprint + 40-bit raw id packed into the existing 64-bit `repoId` slot — sign bit = foreign source), `RepositoryUrlParser` (recognises GitHub + Codeberg + gitea.com + git.disroot.org + user-added forge hosts). System interfaces: `Installer`, `InstallerStatusProvider`, `PackageMonitor`, `SystemInstallSerializer`.
8362  
84−### Navigation
63+## Tech
8564  
86−Type-safe navigation using `@Serializable` sealed interface `GithubStoreGraph` in `composeApp/.../navigation/GithubStoreGraph.kt`. Routes are wired in `AppNavigation.kt`. Parameterized routes: `DetailsScreen(repositoryId, owner, repo, isComingFromUpdate)`, `DeveloperProfileScreen(username)`.
65+Kotlin 2.3.10, Compose Multiplatform 1.10.3, Ktor 3.4.0, Room 2.8.4, Koin 4.1.1, kotlinx.serialization 1.10.0, DataStore 1.2.0, Landscapist 2.9.5, Kermit 2.0.8, MOKO Permissions 0.20.1, Navigation Compose 2.9.2, multiplatform-markdown-renderer 0.39.2, Shizuku 13.1.5, WorkManager 2.11.1, kotlinx.datetime 0.7.1. Versions in `gradle/libs.versions.toml`.
8766  
88−### Dependency Injection
67+## Convention plugins (`build-logic/convention/`)
8968  
90−**Koin** — each feature's data layer defines a module in `data/di/SharedModule.kt`. All modules are registered in `composeApp/.../di/initKoin.kt`. ViewModels injected via `koinViewModel()`. `DetailsViewModel` and `MirrorPickerViewModel` use manual Koin `viewModel { }` with `parametersOf()` for constructor args; all others use `viewModelOf(::ClassName)`.
69+`convention.kmp.library` (domain/data), `convention.cmp.library` (core/presentation), `convention.cmp.feature` (feature presentation), `convention.cmp.application` (main app), `convention.room`, `convention.buildkonfig`.
9170  
92−### Key Cross-Cutting Concerns
71+## Adding a feature
9372  
94−- **Auth flow:** GitHub device-flow OAuth. Primary path goes through backend proxy (`/v1/auth/device/start`, `/v1/auth/device/poll`); falls back to direct GitHub only on infrastructure errors (5xx, timeouts). HTTP 4xx and GitHub's negative 200-bodies never trigger fallback. Backend rate limits (10 starts/hr, 200 polls/hr per IP) are hard — do not add retry loops.
95−- **`X-GitHub-Token` header:** Forwarded on every backend passthrough route — `/v1/search`, `/v1/search/explore`, `/v1/repo/{owner}/{name}`, `/v1/releases/{owner}/{name}`, `/v1/readme/{owner}/{name}`, `/v1/user/{username}`. Backend re-sends as `Authorization: token $token` so upstream GitHub calls run under the user's 5000/hr OAuth quota; without it the request falls back to the shared 60/hr anonymous bucket and a single 4xx can poison the backend's 15-min negative cache for everyone. DB-only routes (`/v1/categories`, `/v1/topics`, `/v1/events`, `/v1/auth/device/*`, `/v1/badge/*`) never get the header. Sourced via `BackendApiClient.currentUserGithubToken()` (`private`), never logged. 401 from passthrough routes ≠ session expired — `AuthenticationStateImpl` debounces consecutive 401s under the same token before clearing the session.
96−- **Platform branching:** Source sets are `commonMain` (shared), `androidMain` (Android), `jvmMain` (Desktop). Some features (apps, installation, Shizuku) are Android-only.
97−- **Shizuku (Android):** Optional silent install via AIDL service. Falls back to standard installer on failure.
73+1. `feature/<name>/{domain,data,presentation}/` with appropriate convention plugin
74+2. `include` in `settings.gradle.kts`
75+3. Domain interfaces → impl + Koin module in `data/di/SharedModule.kt` → ViewModel + Screen
76+4. Route in `GithubStoreGraph.kt` + wire in `AppNavigation.kt` + register Koin in `initKoin.kt`
9877  
99−## Coding Conventions
78+## Key configuration
10079  
101−- Packages: `zed.rainxch.{module}.{layer}` (e.g. `zed.rainxch.home.data.repository`)
102−- Private state: underscore prefix `_state`, `_events`
103−- Sealed classes/interfaces for type-safe routes, actions, events
104−- Repository pattern: interface in `domain/`, implementation in `data/`
105−- Ktlint auto-runs on `preBuild`/`compileKotlin*` tasks; `ignoreFailures = true`
106−- Ktlint rules: wildcard imports allowed, filename rule disabled, `@Composable` functions exempt from function naming rule (see `.editorconfig`)
80+- **GitHub OAuth:** `GITHUB_CLIENT_ID` in `local.properties`. Deep links: `githubstore://auth` (web-OAuth handoff), `githubstore://callback` (legacy device-flow leftover), `githubstore://repo`, `githubstore://apps`.
81+- **Shizuku (Android):** silent install via `ShizukuProvider` → AIDL → `pm install -S`. Fallback to standard installer on failure.
82+- **Desktop logs:** `CrashReporter` (first line of `DesktopApp.main`) tees stdout/stderr to rotating `session.log` + writes `crash-<ts>.log` on uncaught. Paths: `~/Library/Logs/GitHub-Store/` (macOS), `%LOCALAPPDATA%/GitHub-Store/logs/` (Win), `$XDG_STATE_HOME/GitHub-Store/logs/` (Linux). Android = Logcat.
83+- **macOS distribution:** Homebrew cask in tap `openhub-store/tap` (separate repo `homebrew-tap`). `brew install --cask github-store`. Unsigned at present — user must `xattr -dr com.apple.quarantine /Applications/GitHub-Store.app` after install. CI builds `.dmg` + `.pkg` on every push to `generate-installers`; tap cask updates automatically on release.
84+- **`X-GitHub-Token` header:** Client attaches when `TokenStore.currentToken()` is non-null on `/v1/search`, `/v1/search/explore`, `/v1/repo`, `/v1/releases`, `/v1/readme`, `/v1/user`. Backend re-sends as `Authorization: token $token` to GitHub. Without it, backend round-robins a 4-token service pool. Upstream 401 remapped to backend `502` (handled like "GitHub unreachable" — fall back via `shouldFallbackToGithubOrRethrow`). `429` = no fallback (same wall), only backoff. `UnauthorizedInterceptor` only on direct-GitHub client; `AuthenticationStateImpl` debounces consecutive 401s by token snapshot.
85+- **Auth flow (web-OAuth-first):** Primary path is web OAuth with PKCE + handoff. `feature/auth/data/crypto/PkceGenerator` mints `(state, codeVerifier, codeChallenge)`; `WebAuthApi.register` POSTs verifier + challenge + state to `https://github-store.org/auth/register` (Cloudflare Worker stashes them in Workers KV) and returns `authUrl`. User opens it, authorizes on `github.com`, GitHub redirects to `github-store.org/auth/callback?code&state` where the Worker exchanges the code via `api.github-store.org` (backend stores `(handoffId → access_token)` for 60s in Postgres with atomic `DELETE…RETURNING`), then bounces back to `githubstore://auth?h=<handoffId>`. App reads handoff via `WebAuthApi.consumeHandoff` (GETDEL semantics). Secondary path: device flow via backend `/v1/auth/device/start` + `/poll`, `AuthPath` (`Backend`|`Direct`) tracked in `SavedStateHandle`, only escalates `Backend → Direct` on infra errors. Tertiary: paste a Personal Access Token (`signInWithPat` — validates against `/user`, persists optimistically when GitHub unreachable). Backend rate limits: 10 device-starts/hr, 200 device-polls/hr per IP. Endpoints in `core/data/network/BackendEndpoints.kt` (`BACKEND_ORIGIN`, `WEB_ORIGIN`).
86+- **Windows installer signing (SignPath Foundation):** CI workflow `.github/workflows/build-desktop-platforms.yml` job `sign-windows` after every push to `generate-installers` branch. Action pinned to commit SHA (not `@v2`). Secrets: `SIGNPATH_API_TOKEN`, `SIGNPATH_ORGANIZATION_ID` (`1ecf111e-...`). Variable `SIGNPATH_SIGNING_POLICY_SLUG` = `test-signing` until prod cert issued; flip to `release-signing`. Project slug `GitHub-Store`, artifact config slug `initial`. Unsigned artifact deleted post-sign; only `windows-installers-signed` reaches the draft release.
87+- **WinGet publish:** `.github/workflows/winget-publish.yml` fires on `release: [released]`. Action `vedantmgoyal9/winget-releaser@main`. Secret `WINGET_TOKEN` = PAT with `Contents+Pull requests: write` on `OpenHub-Store/winget-pkgs` (fork of `microsoft/winget-pkgs`). Pin `fork-user: OpenHub-Store` explicitly so the action doesn't infer from token owner.
88+- **Forges (Codeberg / Forgejo / Gitea):** `ForgejoApiClient` per host (60s req / 30s connect+socket timeouts, exponential retry on 5xx + IOException). `ForgejoClientRegistry.clientFor(host)` cached + Mutex-guarded. Direct-to-forge — no backend mediator. `RepoIdCodec` packs host fingerprint into `repoId` so the existing GitHub-shaped schema survives. README via `/contents/README.md?ref={branch}` (Forgejo has NO `/readme` endpoint). License sniffed from `/contents/LICENSE` regex against SPDX headers. Downloads aggregated by summing `asset.download_count` across releases.
89+- **Per-host PATs:** `HostTokenRepository` stores `{host, token, label, createdAt}` rows AES-256-GCM encrypted via KSafe. `HostTokenInterceptor` (Ktor plugin) injects `Authorization: token $pat` on matched host. `HostNames.apiHostToTokenHost` maps `api.github.com → github.com` so the GitHub-direct client looks up the right PAT. UI at `Tweaks → Access Tokens` (`HostTokensScreen`).
90+- **KSafe:** AES-256-GCM with hardware-backed Keystore on Android. Wraps every persisted credential / pref via `core/data/secure/KSafeSafe.kt` extension funcs (`safeGet`, `safePut`, `safeDelete`, `safeGetFlow`) — surface log + return null/false on transient failure instead of throwing through coroutine scopes.
91+- **Translation providers:** `TranslationProvider` enum = `GOOGLE`, `YOUDAO`, `LIBRE_TRANSLATE`, `DEEPL`, `MICROSOFT`. Each per-provider config persisted via `TweaksRepository` (KSafe-encrypted). `TranslationRepositoryImpl.resolveTranslator()` picks the impl. LibreTranslate defaults to the bundled `translate.disroot.org` mirror when user URL pref blank. DeepL auto-routes `:fx`-suffixed keys to `api-free.deepl.com`. Microsoft uses No-Trace by default — text never stored, never used for training.
92+- **Gradle:** Config + build cache enabled. 4GB Gradle heap, 3GB Kotlin daemon. Official Kotlin style.
10793  
108−## Adding a New Feature
94+## Active skills (apply on matching domain)
10995  
110−1. Create `feature/<name>/domain/`, `feature/<name>/data/`, `feature/<name>/presentation/`
111−2. Add `build.gradle.kts` in each using the appropriate convention plugin
112−3. Add `include` entries in `settings.gradle.kts`
113−4. Define domain interfaces/models in `domain/`
114−5. Implement repository + Koin DI module in `data/di/SharedModule.kt`
115−6. Create ViewModel (State/Action/Event pattern) and Screen in `presentation/`
116−7. Add navigation route to `GithubStoreGraph.kt` and wire in `AppNavigation.kt`
117−8. Register the Koin module in `initKoin.kt`
96+- **caveman** — session default, terse output.
97+- **karpathy-guidelines** — anti-overcomplication, minimal diffs, surface assumptions, verifiable success criteria. Every coding task.
98+- **one-skill-to-rule-them-all** — watch for skill-capture opportunities during multi-step work.
99+- **gsd-inbox** - Triage open GitHub issues + PRs against templates. Our exact pattern — automate the "check issue #N, draft reply, ship fix" loop.
100+- **gsd-ship** - Create PR + review + prep for merge. Every task ends here.
101+- **gsd-quick** - Trivial task with atomic commits + state tracking. Matches our small-commit policy.
102+- **gsd-debug** - Systematic debugging with persistent state across context resets. For bug-hunt cycles.
103+- **android-* skills** (`~/.claude/skills/android/`) — auto-fire by description match; apply when in matching domain:
104+ - `android-compose-ui` — composables, recomposition, animations, modifiers, design system
105+ - `android-data-layer` — repos, DTOs, Room, Ktor, mappers
106+ - `android-di-koin` — Koin module setup, ViewModel injection
107+ - `android-error-handling` — Result wrapper, typed errors
108+ - `android-module-structure` — feature-layered modules, convention plugins
109+ - `android-navigation` — type-safe Compose nav
110+ - `android-presentation-mvi` — State/Action/Event, Root/Screen split, UiText, SavedStateHandle
111+ - `android-testing` — testing patterns
118112  
119−## Feature-Level Documentation
113+## Conventions
120114  
121−Each `feature/` directory contains its own `CLAUDE.md` with module structure, key interfaces, navigation routes, and implementation notes. Read those for feature-specific guidance.
115+- Packages `zed.rainxch.{module}.{layer}`
116+- Private state fields prefix `_state`
117+- Sealed routes/actions/events
118+- Repository pattern: interface in `domain/`, impl in `data/`
119+- Source sets: `commonMain` shared, `androidMain`, `jvmMain`
120+- **No KDoc, no inline comments** unless the user explicitly asks. No function/class docs. Inline only for non-obvious invariants, tricky concurrency, workarounds. Applies globally.
121+- Feature-specific guidance in each `feature/*/CLAUDE.md`
122122  
123−## Versions
123+## Approach
124124  
125−All library versions managed in `gradle/libs.versions.toml`. Key versions: Kotlin 2.3.10, Compose Multiplatform 1.10.3, Ktor 3.4.0, Room 2.8.4, Koin 4.1.1.
125+- Read existing files before writing. Don't re-read unless changed.
126+- Thorough in reasoning, concise in output.
127+- Skip files over 100KB unless required.
128+- No sycophantic openers or closing fluff.
129+- No emojis or em-dashes.
130+- Do not guess APIs, versions, flags, commit SHAs, or package names. Verify by reading code or docs before asserting, researching if necessary.
126131  

Also from Kynth Studios

Built for the same person as RuleStack

ToolDrift

What the AI coding tools changed last night

tooldrift.kynth.studio

StillShipping

Which agent tools have stopped shipping

stillshipping.kynth.studio

BlockDex

Search inside every shadcn registry

blockdex.kynth.studio

The studio list

One product, taken apart, once a month

Kynth Studios pulls one shipped product open every month — what it does, what it cost to build, what the pipeline behind it looks like, and what the numbers did. One email a month, nothing in between.

Double opt-in — we send one confirmation link and nothing else until you click it.

RuleStack

Built by

Kynth Studios

the studio behind ToolDrift, StillShipping and BlockDex

part of Toolproof, the measurement layer for AI agent tooling

Directory

Configs
Stacks
Compare formats
AGENTS.md vs CLAUDE.md
Cursor rules alternatives
Diff two configs
Best AGENTS.md examples
Best Cursor rules examples
What goes in a CLAUDE.md

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

© 2026 RuleStack. A Kynth Studios product. Changelog

RuleStack

The studio list

One product, taken apart, once a month

Kynth Studios pulls one shipped product open every month — what it does, what it cost to build, what the pipeline behind it looks like, and what the numbers did. One email a month, nothing in between.

Double opt-in — we send one confirmation link and nothing else until you click it.

RuleStack

Built by

Kynth Studios

the studio behind ToolDrift, StillShipping and BlockDex

part of Toolproof, the measurement layer for AI agent tooling

Directory

Configs
Stacks
Compare formats
AGENTS.md vs CLAUDE.md
Cursor rules alternatives
Diff two configs
Best AGENTS.md examples
Best Cursor rules examples
What goes in a CLAUDE.md

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

© 2026 RuleStack. A Kynth Studios product. Changelog

RuleStack

The studio list

One product, taken apart, once a month

Kynth Studios pulls one shipped product open every month — what it does, what it cost to build, what the pipeline behind it looks like, and what the numbers did. One email a month, nothing in between.

Double opt-in — we send one confirmation link and nothing else until you click it.

RuleStack

Built by

Kynth Studios

the studio behind ToolDrift, StillShipping and BlockDex

part of Toolproof, the measurement layer for AI agent tooling

Directory

Configs
Stacks
Compare formats
AGENTS.md vs CLAUDE.md
Cursor rules alternatives
Diff two configs
Best AGENTS.md examples
Best Cursor rules examples
What goes in a CLAUDE.md

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

© 2026 RuleStack. A Kynth Studios product. Changelog

RuleStack