@kodrunhq/opencode-autopilot 1.3.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/commands/brainstorm.md +7 -0
- package/assets/commands/stocktake.md +7 -0
- package/assets/commands/tdd.md +7 -0
- package/assets/commands/update-docs.md +7 -0
- package/assets/commands/write-plan.md +7 -0
- package/assets/skills/brainstorming/SKILL.md +295 -0
- package/assets/skills/code-review/SKILL.md +241 -0
- package/assets/skills/e2e-testing/SKILL.md +266 -0
- package/assets/skills/git-worktrees/SKILL.md +296 -0
- package/assets/skills/go-patterns/SKILL.md +240 -0
- package/assets/skills/plan-executing/SKILL.md +258 -0
- package/assets/skills/plan-writing/SKILL.md +278 -0
- package/assets/skills/python-patterns/SKILL.md +255 -0
- package/assets/skills/rust-patterns/SKILL.md +293 -0
- package/assets/skills/strategic-compaction/SKILL.md +217 -0
- package/assets/skills/systematic-debugging/SKILL.md +299 -0
- package/assets/skills/tdd-workflow/SKILL.md +311 -0
- package/assets/skills/typescript-patterns/SKILL.md +278 -0
- package/assets/skills/verification/SKILL.md +240 -0
- package/package.json +1 -1
- package/src/index.ts +72 -1
- package/src/observability/context-monitor.ts +102 -0
- package/src/observability/event-emitter.ts +136 -0
- package/src/observability/event-handlers.ts +322 -0
- package/src/observability/event-store.ts +226 -0
- package/src/observability/index.ts +53 -0
- package/src/observability/log-reader.ts +152 -0
- package/src/observability/log-writer.ts +93 -0
- package/src/observability/mock/mock-provider.ts +72 -0
- package/src/observability/mock/types.ts +31 -0
- package/src/observability/retention.ts +57 -0
- package/src/observability/schemas.ts +83 -0
- package/src/observability/session-logger.ts +63 -0
- package/src/observability/summary-generator.ts +209 -0
- package/src/observability/token-tracker.ts +97 -0
- package/src/observability/types.ts +24 -0
- package/src/orchestrator/skill-injection.ts +38 -0
- package/src/review/sanitize.ts +1 -1
- package/src/skills/adaptive-injector.ts +122 -0
- package/src/skills/dependency-resolver.ts +88 -0
- package/src/skills/linter.ts +113 -0
- package/src/skills/loader.ts +88 -0
- package/src/templates/skill-template.ts +4 -0
- package/src/tools/create-skill.ts +12 -0
- package/src/tools/logs.ts +178 -0
- package/src/tools/mock-fallback.ts +100 -0
- package/src/tools/pipeline-report.ts +148 -0
- package/src/tools/session-stats.ts +185 -0
- package/src/tools/stocktake.ts +170 -0
- package/src/tools/update-docs.ts +116 -0
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rust-patterns
|
|
3
|
+
description: Rust patterns covering ownership, error handling with Result/Option, unsafe guidelines, and testing conventions
|
|
4
|
+
stacks:
|
|
5
|
+
- rust
|
|
6
|
+
requires: []
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Rust Patterns
|
|
10
|
+
|
|
11
|
+
Idiomatic Rust patterns for writing safe, efficient, and maintainable code. Covers ownership and borrowing, error handling with `Result` and `Option`, unsafe guidelines, testing conventions, crate organization, and common anti-patterns. Apply these when writing, reviewing, or refactoring Rust code.
|
|
12
|
+
|
|
13
|
+
## 1. Ownership and Borrowing
|
|
14
|
+
|
|
15
|
+
**DO:** Leverage Rust's ownership system to write safe code without garbage collection.
|
|
16
|
+
|
|
17
|
+
- Prefer borrowing (`&T`, `&mut T`) over taking ownership when the function doesn't need to own the data:
|
|
18
|
+
```rust
|
|
19
|
+
// DO: Borrow -- caller keeps ownership
|
|
20
|
+
fn process(items: &[Item]) -> Summary { ... }
|
|
21
|
+
|
|
22
|
+
// DON'T: Take ownership unnecessarily
|
|
23
|
+
fn process(items: Vec<Item>) -> Summary { ... }
|
|
24
|
+
```
|
|
25
|
+
- Prefer `&str` over `String` in function parameters:
|
|
26
|
+
```rust
|
|
27
|
+
fn greet(name: &str) -> String {
|
|
28
|
+
format!("Hello, {name}!")
|
|
29
|
+
}
|
|
30
|
+
// Accepts both String and &str via deref coercion
|
|
31
|
+
```
|
|
32
|
+
- Use lifetimes explicitly when the compiler cannot infer them:
|
|
33
|
+
```rust
|
|
34
|
+
struct Parser<'a> {
|
|
35
|
+
input: &'a str,
|
|
36
|
+
position: usize,
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
- Understand move semantics -- types implementing `Copy` are copied, others are moved:
|
|
40
|
+
```rust
|
|
41
|
+
let a = String::from("hello");
|
|
42
|
+
let b = a; // a is MOVED to b, a is no longer valid
|
|
43
|
+
// For Copy types (i32, f64, bool): both remain valid
|
|
44
|
+
```
|
|
45
|
+
- Use `Cow<'_, str>` when a function sometimes needs to allocate and sometimes doesn't:
|
|
46
|
+
```rust
|
|
47
|
+
fn normalize(input: &str) -> Cow<'_, str> {
|
|
48
|
+
if input.contains(' ') {
|
|
49
|
+
Cow::Owned(input.replace(' ', "_"))
|
|
50
|
+
} else {
|
|
51
|
+
Cow::Borrowed(input)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**DON'T:**
|
|
57
|
+
|
|
58
|
+
- Use `Clone` to silence the borrow checker -- fix the ownership design instead
|
|
59
|
+
- Pass `&String` -- pass `&str` (more general, no extra indirection)
|
|
60
|
+
- Use `'static` lifetime unless the data truly lives for the entire program
|
|
61
|
+
- Fight the borrow checker with `Rc<RefCell<T>>` everywhere -- rethink the data flow
|
|
62
|
+
|
|
63
|
+
## 2. Error Handling
|
|
64
|
+
|
|
65
|
+
**DO:** Use `Result<T, E>` for recoverable errors and the `?` operator for ergonomic propagation.
|
|
66
|
+
|
|
67
|
+
- Use `Result<T, E>` for all operations that can fail:
|
|
68
|
+
```rust
|
|
69
|
+
fn parse_config(path: &Path) -> Result<Config, ConfigError> {
|
|
70
|
+
let content = fs::read_to_string(path)?;
|
|
71
|
+
let config: Config = toml::from_str(&content)?;
|
|
72
|
+
Ok(config)
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
- Use `?` for error propagation -- it's Rust's equivalent of Go's `if err != nil`:
|
|
76
|
+
```rust
|
|
77
|
+
fn process() -> Result<Output, AppError> {
|
|
78
|
+
let input = read_input()?; // propagates on Err
|
|
79
|
+
let parsed = parse(input)?; // propagates on Err
|
|
80
|
+
let result = transform(parsed)?; // propagates on Err
|
|
81
|
+
Ok(result)
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
- Use `thiserror` for custom error types in library code:
|
|
85
|
+
```rust
|
|
86
|
+
#[derive(Debug, thiserror::Error)]
|
|
87
|
+
enum AppError {
|
|
88
|
+
#[error("config error: {0}")]
|
|
89
|
+
Config(#[from] ConfigError),
|
|
90
|
+
#[error("database error: {0}")]
|
|
91
|
+
Database(#[from] sqlx::Error),
|
|
92
|
+
#[error("not found: {resource}")]
|
|
93
|
+
NotFound { resource: String },
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
- Use `anyhow::Result` in application code (binaries, CLI tools) where you don't need typed errors:
|
|
97
|
+
```rust
|
|
98
|
+
fn main() -> anyhow::Result<()> {
|
|
99
|
+
let config = load_config().context("failed to load config")?;
|
|
100
|
+
run(config)?;
|
|
101
|
+
Ok(())
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
- Add context to errors with `.context()` or `.with_context()`:
|
|
105
|
+
```rust
|
|
106
|
+
fs::read_to_string(path)
|
|
107
|
+
.with_context(|| format!("failed to read {}", path.display()))?;
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**DON'T:**
|
|
111
|
+
|
|
112
|
+
- Use `panic!` for recoverable errors -- `panic!` is for bugs, not expected failures
|
|
113
|
+
- Use `.unwrap()` in production code -- use `?`, `.unwrap_or_default()`, or explicit match
|
|
114
|
+
- Create error types without `#[derive(Debug)]` -- debug formatting is essential for logging
|
|
115
|
+
- Return `Box<dyn Error>` in library code -- use typed errors for caller inspection
|
|
116
|
+
|
|
117
|
+
## 3. Option Patterns
|
|
118
|
+
|
|
119
|
+
**DO:** Use `Option<T>` instead of null/sentinel values, and prefer combinators over manual matching.
|
|
120
|
+
|
|
121
|
+
- Use combinators for clean transformations:
|
|
122
|
+
```rust
|
|
123
|
+
let display_name = user.nickname
|
|
124
|
+
.map(|n| format!("@{n}"))
|
|
125
|
+
.unwrap_or_else(|| user.full_name.clone());
|
|
126
|
+
```
|
|
127
|
+
- Use `if let` for conditional extraction:
|
|
128
|
+
```rust
|
|
129
|
+
if let Some(config) = load_optional_config() {
|
|
130
|
+
apply(config);
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
- Use `?` with `Option` in functions returning `Option`:
|
|
134
|
+
```rust
|
|
135
|
+
fn get_user_email(db: &Database, id: UserId) -> Option<String> {
|
|
136
|
+
let user = db.find_user(id)?; // returns None if not found
|
|
137
|
+
Some(user.email.clone())
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
- Chain operations with `.and_then()` for flat-mapping:
|
|
141
|
+
```rust
|
|
142
|
+
let port: Option<u16> = env::var("PORT").ok().and_then(|s| s.parse().ok());
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
**DON'T:**
|
|
146
|
+
|
|
147
|
+
- Use `.unwrap()` outside of tests -- it panics on `None`
|
|
148
|
+
- Use sentinel values (`-1`, `""`, `0`) when `Option` expresses the intent clearly
|
|
149
|
+
- Match when a combinator is more concise -- `option.map(f)` beats `match option { Some(v) => Some(f(v)), None => None }`
|
|
150
|
+
- Use `Option<Option<T>>` -- it's confusing. Use an enum with explicit variants instead
|
|
151
|
+
|
|
152
|
+
## 4. Unsafe Guidelines
|
|
153
|
+
|
|
154
|
+
**DO:** Minimize unsafe code and encapsulate it behind safe abstractions.
|
|
155
|
+
|
|
156
|
+
- Wrap every `unsafe` block in a safe function with documented invariants:
|
|
157
|
+
```rust
|
|
158
|
+
/// Returns a reference to the element at `index` without bounds checking.
|
|
159
|
+
///
|
|
160
|
+
/// # Safety
|
|
161
|
+
/// Caller must ensure `index < self.len()`.
|
|
162
|
+
pub unsafe fn get_unchecked(&self, index: usize) -> &T { ... }
|
|
163
|
+
```
|
|
164
|
+
- Document every `unsafe` block with a `// SAFETY:` comment explaining the invariant:
|
|
165
|
+
```rust
|
|
166
|
+
// SAFETY: We checked that index < len on the line above.
|
|
167
|
+
let value = unsafe { slice.get_unchecked(index) };
|
|
168
|
+
```
|
|
169
|
+
- Keep `unsafe` blocks as small as possible -- one operation per block
|
|
170
|
+
- Prefer safe alternatives in all cases:
|
|
171
|
+
- `Vec<T>` over raw pointers and manual allocation
|
|
172
|
+
- `Arc<Mutex<T>>` over shared mutable raw pointers
|
|
173
|
+
- `std::sync::atomic` over `unsafe` for atomic operations
|
|
174
|
+
- `crossbeam` or channels over `unsafe` for concurrent data structures
|
|
175
|
+
|
|
176
|
+
**DON'T:**
|
|
177
|
+
|
|
178
|
+
- Use `unsafe` for performance without benchmarks proving it's necessary
|
|
179
|
+
- Use `transmute` -- it's almost never the right answer. Use `from_ne_bytes`, `TryFrom`, or safe casts
|
|
180
|
+
- Dereference raw pointers without validating alignment and lifetime
|
|
181
|
+
- Implement `Send` or `Sync` manually unless you deeply understand the invariants
|
|
182
|
+
- Use `unsafe` to bypass the borrow checker -- it means the design is wrong
|
|
183
|
+
|
|
184
|
+
## 5. Testing
|
|
185
|
+
|
|
186
|
+
**DO:** Write unit tests in the same file and integration tests in `tests/`.
|
|
187
|
+
|
|
188
|
+
- Unit tests in the same file with `#[cfg(test)]`:
|
|
189
|
+
```rust
|
|
190
|
+
#[cfg(test)]
|
|
191
|
+
mod tests {
|
|
192
|
+
use super::*;
|
|
193
|
+
|
|
194
|
+
#[test]
|
|
195
|
+
fn parse_valid_config() {
|
|
196
|
+
let config = parse_config("key = \"value\"").unwrap();
|
|
197
|
+
assert_eq!(config.key, "value");
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
#[test]
|
|
201
|
+
fn parse_empty_returns_error() {
|
|
202
|
+
assert!(parse_config("").is_err());
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
- Use `#[should_panic]` for expected panics:
|
|
207
|
+
```rust
|
|
208
|
+
#[test]
|
|
209
|
+
#[should_panic(expected = "index out of bounds")]
|
|
210
|
+
fn panics_on_invalid_index() {
|
|
211
|
+
get_item(&[], 0);
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
- Use `assert_eq!` with descriptive messages:
|
|
215
|
+
```rust
|
|
216
|
+
assert_eq!(result, expected, "failed for input: {input:?}");
|
|
217
|
+
```
|
|
218
|
+
- Integration tests in `tests/` directory access only the public API:
|
|
219
|
+
```
|
|
220
|
+
tests/
|
|
221
|
+
integration_test.rs
|
|
222
|
+
common/
|
|
223
|
+
mod.rs // shared test helpers
|
|
224
|
+
```
|
|
225
|
+
- Use `proptest` or `quickcheck` for property-based testing:
|
|
226
|
+
```rust
|
|
227
|
+
proptest! {
|
|
228
|
+
#[test]
|
|
229
|
+
fn roundtrip_serialize(value: MyType) {
|
|
230
|
+
let bytes = serialize(&value);
|
|
231
|
+
let decoded = deserialize(&bytes).unwrap();
|
|
232
|
+
assert_eq!(value, decoded);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
- Use `#[ignore]` for slow tests with a reason: `#[ignore = "requires database"]`
|
|
237
|
+
|
|
238
|
+
**DON'T:**
|
|
239
|
+
|
|
240
|
+
- Put test utilities in the main `src/` tree -- use `tests/common/` or a `dev-dependencies` crate
|
|
241
|
+
- Use `.unwrap()` in tests without context -- prefer `.expect("reason")` for better panic messages
|
|
242
|
+
- Test private implementation details -- test through the public API
|
|
243
|
+
- Skip `#[cfg(test)]` on the test module -- tests will be compiled into release builds
|
|
244
|
+
|
|
245
|
+
## 6. Crate Organization
|
|
246
|
+
|
|
247
|
+
**DO:** Organize crates for clarity and minimal compilation units.
|
|
248
|
+
|
|
249
|
+
- Use a workspace for multi-crate projects:
|
|
250
|
+
```toml
|
|
251
|
+
# Cargo.toml (workspace root)
|
|
252
|
+
[workspace]
|
|
253
|
+
members = ["crates/*"]
|
|
254
|
+
```
|
|
255
|
+
- Separate library and binary crates:
|
|
256
|
+
```
|
|
257
|
+
src/
|
|
258
|
+
lib.rs # library logic
|
|
259
|
+
main.rs # thin entry point calling lib
|
|
260
|
+
```
|
|
261
|
+
- Use `pub(crate)` for internal visibility -- not everything needs to be fully public
|
|
262
|
+
- Group related types in modules:
|
|
263
|
+
```rust
|
|
264
|
+
// src/lib.rs
|
|
265
|
+
pub mod config;
|
|
266
|
+
pub mod error;
|
|
267
|
+
pub mod client;
|
|
268
|
+
```
|
|
269
|
+
- Keep `main.rs` thin -- parse args, configure logging, call library functions
|
|
270
|
+
|
|
271
|
+
**DON'T:**
|
|
272
|
+
|
|
273
|
+
- Put everything in `lib.rs` -- split into modules when the file exceeds 400 lines
|
|
274
|
+
- Use `pub` on everything -- default to private, expose only what's needed
|
|
275
|
+
- Create deep module hierarchies -- flat is better than nested
|
|
276
|
+
- Use `mod.rs` files (old style) -- prefer `module_name.rs` (2018 edition style)
|
|
277
|
+
|
|
278
|
+
## 7. Anti-Pattern Catalog
|
|
279
|
+
|
|
280
|
+
**Anti-Pattern: Unnecessary Clone**
|
|
281
|
+
Calling `.clone()` to satisfy the borrow checker without understanding why it's needed. Cloning hides design problems -- if you need to clone, ask whether the ownership model is correct. Instead: restructure code to use references, or use `Cow<'_, T>` when cloning is sometimes needed.
|
|
282
|
+
|
|
283
|
+
**Anti-Pattern: Unwrap Everywhere**
|
|
284
|
+
Sprinkling `.unwrap()` in production code because "it should never be None/Err". It will be, and it will panic at 3am. Instead: use `?` for propagation, `.unwrap_or_default()` for safe defaults, or `match`/`if let` for explicit handling.
|
|
285
|
+
|
|
286
|
+
**Anti-Pattern: Stringly Typed**
|
|
287
|
+
Using `String` for everything -- status codes, identifiers, categories. Strings have no compile-time validation. Instead: use newtypes (`struct UserId(String)`) and enums (`enum Status { Active, Inactive }`) for domain concepts.
|
|
288
|
+
|
|
289
|
+
**Anti-Pattern: Over-Generic Functions**
|
|
290
|
+
`fn process<T: Debug + Clone + Send + Sync + 'static>(item: T)` when the function only ever processes `Widget`. Generics should be introduced when there are 2+ concrete types that need the same logic. Instead: start concrete, generalize when needed.
|
|
291
|
+
|
|
292
|
+
**Anti-Pattern: Ignoring Clippy**
|
|
293
|
+
Adding `#[allow(clippy::...)]` instead of fixing the lint. Clippy catches real bugs (unnecessary allocations, logic errors, unidiomatic code). Instead: fix the issue. If the lint is genuinely wrong, add a comment explaining why.
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: strategic-compaction
|
|
3
|
+
description: Context window management through strategic summarization -- keep working memory lean without losing critical information
|
|
4
|
+
stacks: []
|
|
5
|
+
requires: []
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Strategic Compaction
|
|
9
|
+
|
|
10
|
+
Context window management through strategic summarization. When your working context grows large, compaction keeps you productive by preserving what matters and discarding what does not. This skill teaches when to compact, what to keep, and how to rebuild context from a summary.
|
|
11
|
+
|
|
12
|
+
## When to Use
|
|
13
|
+
|
|
14
|
+
- Context window is filling up (more than 60% used)
|
|
15
|
+
- Working on a long task spanning many files
|
|
16
|
+
- Need to switch subtasks without losing prior context
|
|
17
|
+
- Session is slowing down or responses are becoming less detailed
|
|
18
|
+
- You are about to start a new phase of work that does not need the details of the previous phase
|
|
19
|
+
- After completing a major subtask and before starting the next
|
|
20
|
+
|
|
21
|
+
## The Compaction Process
|
|
22
|
+
|
|
23
|
+
Compaction is a four-step process. Follow each step in order.
|
|
24
|
+
|
|
25
|
+
### Step 1: Identify What to Keep
|
|
26
|
+
|
|
27
|
+
These items are essential and must survive compaction:
|
|
28
|
+
|
|
29
|
+
- **Current task requirements** -- the active goal and acceptance criteria
|
|
30
|
+
- **Key decisions made so far** -- and the rationale behind each one (the WHY is more important than the WHAT)
|
|
31
|
+
- **File paths and function signatures** -- for files currently being modified or about to be modified
|
|
32
|
+
- **Error messages and test failures** -- if you are actively investigating or debugging
|
|
33
|
+
- **Constraints and invariants** -- rules that must not be violated (security requirements, API contracts, performance budgets)
|
|
34
|
+
- **Dependency relationships** -- what depends on what, what must be done in order
|
|
35
|
+
|
|
36
|
+
### Step 2: Identify What to Compact
|
|
37
|
+
|
|
38
|
+
These items can be summarized or discarded:
|
|
39
|
+
|
|
40
|
+
- **File contents already read and understood** -- keep only the path plus the key insight (e.g., "src/auth.ts: JWT validation using jose library, exports verifyToken()")
|
|
41
|
+
- **Exploration dead ends** -- reduce to one line: "Tried approach X, did not work because Y"
|
|
42
|
+
- **Verbose tool output** -- keep the conclusion, discard the raw output (e.g., "Tests pass: 47/47" instead of the full test runner output)
|
|
43
|
+
- **Background context not needed for the current subtask** -- prior phase decisions that are not relevant to what you are doing right now
|
|
44
|
+
- **Completed work details** -- reduce to "Task N done: implemented feature X in file Y" with the commit hash
|
|
45
|
+
|
|
46
|
+
### Step 3: Create a Summary
|
|
47
|
+
|
|
48
|
+
Structure your summary using this template:
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
## Working Context Summary
|
|
52
|
+
|
|
53
|
+
**Goal:** [one sentence describing the active objective]
|
|
54
|
+
|
|
55
|
+
**Key Decisions:**
|
|
56
|
+
- [Decision 1]: [rationale]
|
|
57
|
+
- [Decision 2]: [rationale]
|
|
58
|
+
|
|
59
|
+
**Current State:**
|
|
60
|
+
- Done: [what has been completed]
|
|
61
|
+
- In Progress: [what is currently being worked on]
|
|
62
|
+
- Next: [what comes after the current task]
|
|
63
|
+
|
|
64
|
+
**Active Files:**
|
|
65
|
+
- [path]: [what you are doing with this file]
|
|
66
|
+
- [path]: [key insight about this file]
|
|
67
|
+
|
|
68
|
+
**Constraints:**
|
|
69
|
+
- [constraint 1]
|
|
70
|
+
- [constraint 2]
|
|
71
|
+
|
|
72
|
+
**Errors/Blockers:**
|
|
73
|
+
- [any active issues being investigated]
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Target 500-1000 tokens for the summary. This is your restore point -- it should contain everything needed to resume work without re-reading files.
|
|
77
|
+
|
|
78
|
+
### Step 4: Apply Compaction
|
|
79
|
+
|
|
80
|
+
When starting a new session or after context reset:
|
|
81
|
+
|
|
82
|
+
1. Load the summary first -- this is your map
|
|
83
|
+
2. Read only the files actively being modified (the "Active Files" list)
|
|
84
|
+
3. Re-read constraints and interfaces only if you need to verify a specific detail
|
|
85
|
+
4. Do NOT re-read files that were already summarized unless you need to edit them
|
|
86
|
+
|
|
87
|
+
## What to NEVER Compact
|
|
88
|
+
|
|
89
|
+
Some information is too dangerous to summarize. Always keep these in full:
|
|
90
|
+
|
|
91
|
+
- **Active error messages being debugged** -- the exact error text matters for diagnosis
|
|
92
|
+
- **Type definitions and interfaces being implemented against** -- approximate types lead to type errors
|
|
93
|
+
- **Test expectations being satisfied** -- the exact assertion values matter
|
|
94
|
+
- **Security constraints and validation rules** -- approximate security is no security
|
|
95
|
+
- **API contracts with external systems** -- exact field names, types, and required headers
|
|
96
|
+
- **Migration scripts in progress** -- partial migration state is dangerous to approximate
|
|
97
|
+
|
|
98
|
+
## Compaction Strategies by Scenario
|
|
99
|
+
|
|
100
|
+
### Scenario: Multi-File Refactoring
|
|
101
|
+
|
|
102
|
+
You have read 15 files and identified the refactoring pattern. Compact by keeping:
|
|
103
|
+
- The list of files to modify (paths only)
|
|
104
|
+
- The transformation pattern (e.g., "replace direct DB calls with repository pattern")
|
|
105
|
+
- Files already transformed (path + done status)
|
|
106
|
+
- The next file to transform
|
|
107
|
+
|
|
108
|
+
### Scenario: Debugging a Complex Issue
|
|
109
|
+
|
|
110
|
+
You have explored multiple hypotheses. Compact by keeping:
|
|
111
|
+
- The symptom (exact error message)
|
|
112
|
+
- Hypotheses tested and their results (one line each)
|
|
113
|
+
- Current hypothesis being investigated
|
|
114
|
+
- Files relevant to the current hypothesis
|
|
115
|
+
|
|
116
|
+
### Scenario: Implementing a Feature Across Layers
|
|
117
|
+
|
|
118
|
+
You are building a feature that touches API, service, and data layers. Compact by keeping:
|
|
119
|
+
- The feature requirements
|
|
120
|
+
- Interface contracts between layers (function signatures, types)
|
|
121
|
+
- Which layers are done, which are in progress
|
|
122
|
+
- Test status for completed layers
|
|
123
|
+
|
|
124
|
+
## Anti-Pattern Catalog
|
|
125
|
+
|
|
126
|
+
### Anti-Pattern: Compacting Too Early
|
|
127
|
+
|
|
128
|
+
**What it looks like:** Summarizing after reading just 2-3 files, before you have a full picture of the problem space.
|
|
129
|
+
|
|
130
|
+
**Why it is harmful:** You do not yet know what is important. Early summaries miss critical context that you discover later.
|
|
131
|
+
|
|
132
|
+
**Instead:** Compact when context is more than 60% full, or when you are transitioning between major subtasks. Not before.
|
|
133
|
+
|
|
134
|
+
### Anti-Pattern: Losing Key Decisions
|
|
135
|
+
|
|
136
|
+
**What it looks like:** Summarizing away the reasoning behind a decision, keeping only the outcome.
|
|
137
|
+
|
|
138
|
+
**Why it is harmful:** Without the WHY, you (or a future session) may revisit and reverse a well-reasoned decision, wasting time.
|
|
139
|
+
|
|
140
|
+
**Instead:** Always keep decision rationale. "Chose JWT over session cookies because the API is stateless and serves mobile clients" -- not just "Using JWT."
|
|
141
|
+
|
|
142
|
+
### Anti-Pattern: Over-Compacting
|
|
143
|
+
|
|
144
|
+
**What it looks like:** Reducing context to a single paragraph that says "working on auth feature."
|
|
145
|
+
|
|
146
|
+
**Why it is harmful:** Too little context means you have to re-read everything, defeating the purpose of compaction.
|
|
147
|
+
|
|
148
|
+
**Instead:** Keep file paths, function signatures, decision rationale, and current task state. The summary should be 500-1000 tokens, not 50.
|
|
149
|
+
|
|
150
|
+
### Anti-Pattern: Never Compacting
|
|
151
|
+
|
|
152
|
+
**What it looks like:** Accumulating context until the window is full and responses degrade.
|
|
153
|
+
|
|
154
|
+
**Why it is harmful:** The last 20% of the context window produces worse results. By the time you notice degradation, you have already lost quality.
|
|
155
|
+
|
|
156
|
+
**Instead:** Proactively compact when you pass 60% usage, or at natural transition points between subtasks.
|
|
157
|
+
|
|
158
|
+
### Anti-Pattern: Compacting Active Work
|
|
159
|
+
|
|
160
|
+
**What it looks like:** Summarizing files you are still actively editing, losing the detailed state.
|
|
161
|
+
|
|
162
|
+
**Why it is harmful:** You will need to re-read those files immediately, wasting the effort of compaction.
|
|
163
|
+
|
|
164
|
+
**Instead:** Only compact information from COMPLETED subtasks. Keep active work in full detail.
|
|
165
|
+
|
|
166
|
+
## Failure Modes
|
|
167
|
+
|
|
168
|
+
### Summary Is Too Vague
|
|
169
|
+
|
|
170
|
+
**Symptom:** After loading the summary, you do not know which file to open or what to do next.
|
|
171
|
+
|
|
172
|
+
**Fix:** Add specific file paths, function names, and the exact next action. A good summary answers: "What file do I open first, and what do I do in it?"
|
|
173
|
+
|
|
174
|
+
### Lost Critical Context
|
|
175
|
+
|
|
176
|
+
**Symptom:** You make a mistake that contradicts a decision or constraint from the compacted context.
|
|
177
|
+
|
|
178
|
+
**Fix:** The information is on disk -- re-read the relevant files. Then update your summary to include the missing constraint. This is recoverable, not catastrophic.
|
|
179
|
+
|
|
180
|
+
### Summary Is Too Long
|
|
181
|
+
|
|
182
|
+
**Symptom:** The summary itself is 2000+ tokens and does not fit well as a context primer.
|
|
183
|
+
|
|
184
|
+
**Fix:** Focus on what is needed for the NEXT task, not everything done so far. Completed work can be reduced to one line per task. Only the current and next tasks need detail.
|
|
185
|
+
|
|
186
|
+
### Rebuilt Context Drifts from Original
|
|
187
|
+
|
|
188
|
+
**Symptom:** After loading a summary and re-reading files, you reach a different understanding than before compaction.
|
|
189
|
+
|
|
190
|
+
**Fix:** Include concrete artifacts in your summary (exact function signatures, test names, error messages) rather than prose descriptions. Concrete details resist drift; abstract descriptions invite reinterpretation.
|
|
191
|
+
|
|
192
|
+
## Compaction Checklist
|
|
193
|
+
|
|
194
|
+
Use this checklist before and after compaction to ensure quality:
|
|
195
|
+
|
|
196
|
+
### Before Compacting
|
|
197
|
+
|
|
198
|
+
- [ ] Context is more than 60% full OR you are transitioning between major subtasks
|
|
199
|
+
- [ ] You have completed a logical unit of work (not mid-task)
|
|
200
|
+
- [ ] You are not actively debugging an error (keep full error context)
|
|
201
|
+
- [ ] You have identified the next task clearly
|
|
202
|
+
|
|
203
|
+
### Writing the Summary
|
|
204
|
+
|
|
205
|
+
- [ ] Goal is stated in one sentence
|
|
206
|
+
- [ ] Every key decision includes its rationale (the WHY)
|
|
207
|
+
- [ ] Active file paths are listed with their purpose
|
|
208
|
+
- [ ] Current state is explicit (done, in progress, next)
|
|
209
|
+
- [ ] Constraints and invariants are preserved verbatim
|
|
210
|
+
- [ ] Summary is between 500 and 1000 tokens
|
|
211
|
+
|
|
212
|
+
### After Loading a Summary
|
|
213
|
+
|
|
214
|
+
- [ ] You know which file to open first
|
|
215
|
+
- [ ] You know what action to take next
|
|
216
|
+
- [ ] You have not re-read files unnecessarily
|
|
217
|
+
- [ ] If anything is unclear, you re-read the specific source file (not everything)
|