Skip to content

Commit d1b5170

Browse files
committed
feat: Add rules and setup for AI agents
1 parent 6ccbe4f commit d1b5170

File tree

3 files changed

+220
-1
lines changed

3 files changed

+220
-1
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"permissions": {
3+
"allow": [
4+
"Bash",
5+
"Read",
6+
"Edit",
7+
"Write",
8+
"WebFetch",
9+
"mcp__ide__getDiagnostics",
10+
"WebSearch",
11+
"mcp__github__pull_request_read",
12+
"mcp__github__search_pull_requests",
13+
"mcp__github__list_pull_requests",
14+
"mcp__github__get_me",
15+
"mcp__github__get_file_contents"
16+
],
17+
"deny": [],
18+
"ask": [
19+
"Bash(rm -rf:*)",
20+
"Bash(git commit:*)",
21+
"Bash(git push:*)"
22+
],
23+
"additionalDirectories": [
24+
]
25+
}
26+
}

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ local.properties
1212
.ai
1313
.cursor
1414
*.local.*
15-
CLAUDE.md
15+
!*.local.template*
1616
# Secrets
1717
google-services.json
1818
.env

AGENTS.md

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to AI agents like Cursor/Claude Code/Codex/WARP when working with code in this repository.
4+
5+
## Build Commands
6+
7+
```sh
8+
# compile
9+
./gradlew compileDevDebugKotlin
10+
11+
# Build for dev
12+
./gradlew assembleDevDebug
13+
14+
# Run unit tests
15+
./gradlew testDevDebugUnitTest
16+
17+
# Run specific unit test file
18+
./gradlew testDevDebugUnitTest --tests LightningRepoTest
19+
20+
# Run instrumented tests
21+
./gradlew connectedDevDebugAndroidTest
22+
23+
# Build for E2E tests
24+
E2E=true ./gradlew assembleDevRelease
25+
26+
# Build for E2E tests with geoblocking disabled
27+
GEO=false E2E=true ./gradlew assembleDevRelease
28+
29+
# Lint using detekt
30+
./gradlew detekt
31+
32+
# Auto-format using detekt
33+
./gradlew detekt --auto-correct
34+
35+
# Update detekt baseline
36+
./gradlew detektBaseline
37+
38+
# Install dev build
39+
./gradlew installDevDebug
40+
41+
# Clean build artifacts
42+
./gradlew clean
43+
```
44+
45+
## Architecture Overview
46+
47+
### Tech Stack
48+
- **Language**: Kotlin
49+
- **UI Framework**: Jetpack Compose with Material3
50+
- **Architecture**: MVVM with Hilt dependency injection
51+
- **Database**: Room
52+
- **Networking**: Ktor
53+
- **Bitcoin/Lightning**: LDK Node, bitkitcore library
54+
- **State Management**: StateFlow, SharedFlow
55+
- **Navigation**: Compose Navigation with strongly typed routes
56+
- **Push Notifications**: Firebase
57+
- **Storage**: DataStore with json files
58+
59+
### Project Structure
60+
- **app/src/main/java/to/bitkit/**
61+
- **App.kt**: Application class with Hilt setup
62+
- **ui/**: All UI components
63+
- **MainActivity.kt**: Single activity hosting all screens
64+
- **screens/**: Feature-specific screens organized by domain
65+
- **components/**: Reusable UI components
66+
- **theme/**: Material3 theme configuration
67+
- **viewmodels/**: Shared ViewModels for business logic
68+
- **repositories/**: Data access layer
69+
- **services/**: Core services (Lightning, Currency, etc.)
70+
- **data/**: Data layer: database, DTOs, and data stores
71+
- **di/**: Dependency Injection: Hilt modules
72+
- **models/**: Domain models
73+
- **ext/**: Kotlin extensions
74+
- **utils/**: Utility functions
75+
- **usecases/**: Domain layer: use cases
76+
77+
### Key Architecture Patterns
78+
1. **Single Activity Architecture**: MainActivity hosts all screens via Compose Navigation
79+
2. **Repository Pattern**: Repositories abstract data sources from ViewModels
80+
3. **Service Layer**: Core business logic in services (LightningService, WalletService)
81+
4. **Reactive State Management**: ViewModels expose UI state via StateFlow
82+
5. **Coroutine-based Async**: All async operations use Kotlin coroutines
83+
84+
### Build Variants
85+
- **dev**: Regtest network for development
86+
- **tnet**: Testnet network
87+
- **mainnet**: Production (currently commented out)
88+
89+
## Common Pitfalls
90+
91+
### ❌ DON'T
92+
```kotlin
93+
GlobalScope.launch { } // Use viewModelScope
94+
val result = nullable!!.doSomething() // Use safe calls
95+
Text("Send Payment") // Use string resources
96+
class Service(@Inject val vm: ViewModel) // Never inject VMs
97+
suspend fun getData() = runBlocking { } // Use withContext
98+
```
99+
100+
### ✅ DO
101+
```kotlin
102+
viewModelScope.launch { }
103+
val result = nullable?.doSomething() ?: default
104+
Text(stringResource(R.string.send_payment))
105+
class Service { fun process(data: Data) }
106+
suspend fun getData() = withContext(Dispatchers.IO) { }
107+
```
108+
109+
## Key File Paths
110+
111+
- **Main Activity**: `app/src/main/java/to/bitkit/ui/MainActivity.kt`
112+
- **Navigation**: `app/src/main/java/to/bitkit/ui/ContentView.kt`
113+
- **Lightning Service**: `app/src/main/java/to/bitkit/services/LightningService.kt`
114+
- **App ViewModel**: `app/src/main/java/to/bitkit/viewmodels/AppViewModel.kt`
115+
- **Wallet ViewModel**: `app/src/main/java/to/bitkit/viewmodels/WalletViewModel.kt`
116+
117+
## Common Patterns
118+
119+
### ViewModel State
120+
```kotlin
121+
private val _uiState = MutableStateFlow(InitialState)
122+
val uiState: StateFlow<UiState> = _uiState.asStateFlow()
123+
124+
fun updateState(action: Action) {
125+
viewModelScope.launch {
126+
_uiState.update { it.copy(/* fields */) }
127+
}
128+
}
129+
```
130+
131+
### Repository
132+
```kotlin
133+
suspend fun getData(): Result<Data> = withContext(Dispatchers.IO) {
134+
runCatching {
135+
Result.success(apiService.fetchData())
136+
}.onFailure { e ->
137+
Logger.error("Failed", e = e, context = TAG)
138+
}
139+
}
140+
```
141+
142+
### Rules
143+
- USE coding rules from `.cursor/default.rules.mdc`
144+
- ALWAYS run `./gradlew compileDevDebugKotlin` after code changes to verify code compiles
145+
- ALWAYS run `./gradlew testDevDebugUnitTest` after code changes to verify tests succeed and fix accordingly
146+
- ALWAYS run `./gradlew detekt` after code changes to check for new lint issues and fix accordingly
147+
- ALWAYS when fixing lint or test failures prefer to do the minimal amount of changes to fix the issues
148+
- USE single-line commit messages under 50 chars; use template format: `feat: add something new`
149+
- USE `git diff HEAD sourceFilePath` to diff an uncommitted file against the last commit
150+
- ALWAYS check existing code patterns before implementing new features
151+
- USE existing extensions and utilities rather than creating new ones
152+
- ALWAYS consider applying YAGNI (You Aren't Gonna Need It) principle for new code
153+
- ALWAYS reuse existing constants
154+
- ALWAYS ensure a method exist before calling it
155+
- ALWAYS remove unused code after refactors
156+
- ALWAYS follow Material3 design guidelines for UI components
157+
- ALWAYS ensure proper error handling in coroutines
158+
- ALWAYS acknowledge datastore async operations run synchronously in a suspend context
159+
- NEVER use `runBlocking` in suspend functions
160+
- ALWAYS pass the TAG as context to `Logger` calls, e.g. `Logger.debug("message", context = TAG)`
161+
- ALWAYS use the Result API instead of try-catch
162+
- NEVER wrap methods returning `Result<T>` in try-catch
163+
- NEVER inject ViewModels as dependencies - Only android activities and composable functions can use viewmodels
164+
- NEVER hardcode strings and always preserve string resources
165+
- ALWAYS localize in ViewModels using injected `@ApplicationContext`, e.g. `context.getString()`
166+
- ALWAYS use `remember` for expensive Compose computations
167+
- ALWAYS add modifiers to the last place in the argument list when calling `@Composable` functions
168+
- PREFER declaring small dependant classes, constants, interfaces or top-level functions in the same file with the core class where these are used
169+
- ALWAYS create data classes for state AFTER viewModel class in same file
170+
- ALWAYS return early where applicable, PREFER guard-like `if` conditions like `if (condition) return`
171+
- ALWAYS write the documentation for new features as markdown files in `docs/`
172+
- NEVER write code in the documentation files
173+
- NEVER add code comments to private functions, classes, etc
174+
- ALWAYS use `_uiState.update { }`, NEVER use `_stateFlow.value =`
175+
- ALWAYS add the warranted changes in unit tests to keep the unit tests succeeding
176+
- ALWAYS follow the patterns of the existing code in `app/src/test` when writing new unit tests
177+
- ALWAYS be mindful of thread safety when working with mutable lists & state
178+
- ALWAYS split screen composables into parent accepting viewmodel + inner private child accepting state and callbacks `Content()`
179+
- ALWAYS name lambda parameters in a composable function using present tense, NEVER use past tense
180+
- ALWAYS list 3 suggested commit messages after implementation work
181+
- NEVER use `wheneverBlocking` when in an unit test where you're using expression body and already wrapping the test with a `= test {}` lambda.
182+
- ALWAYS add business logic to Repository layer via methods returning `Result<T>` and use it in ViewModels
183+
- ALWAYS use services to wrap RUST code exposed via bindings
184+
- ALWAYS order upstream architectural data flow this way: `UI -> ViewModel -> Repository -> RUST` and vice-versa for downstream
185+
- ALWAYS add new string string resources in alphabetical order in `strings.xml`
186+
- ALWAYS use template in `.github/pull_request_template.md` for PR descriptions
187+
- ALWAYS wrap `ULong` numbers with `USat` in arithmetic operations, to guard against overflows
188+
189+
### Architecture Guidelines
190+
- Use `LightningNodeService` to manage background notifications while the node is running
191+
- Use `LightningService` to wrap node's RUST APIs and manage the inner lifecycle of the node
192+
- Use `LightningRepo` to defining the business logic for the node operations, usually delegating to `LightningService`
193+
- Use `WakeNodeWorker` to manage the handling of remote notifications received via cloud messages

0 commit comments

Comments
 (0)