triples-agentic 2.4.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/LICENSE +21 -0
- package/README.md +326 -0
- package/docs/workflow.md +163 -0
- package/install.sh +98 -0
- package/package.json +54 -0
- package/src/agents/README.md +85 -0
- package/src/agents/jiwoo-prd.md +84 -0
- package/src/agents/kaede-backend.md +95 -0
- package/src/agents/kotone-flutter.md +100 -0
- package/src/agents/lynn-testcase.md +92 -0
- package/src/agents/nakyoung-tasks.md +89 -0
- package/src/agents/seoyeon.md +76 -0
- package/src/agents/shion-qa.md +89 -0
- package/src/agents/sohyun-ios.md +97 -0
- package/src/agents/yeonji-android.md +98 -0
- package/src/agents/yooyeon-rfc.md +82 -0
- package/src/agents/yubin-frontend.md +88 -0
- package/src/bin/setup.js +640 -0
- package/src/hooks/README.md +102 -0
- package/src/hooks/dangerous-commands.json +33 -0
- package/src/hooks/dangerous-commands.md +18 -0
- package/src/knowledge/README.md +129 -0
- package/src/knowledge/general/boy-scout-rule.md +13 -0
- package/src/knowledge/general/composition-over-inheritance.md +14 -0
- package/src/knowledge/general/dry.md +14 -0
- package/src/knowledge/general/fail-fast.md +13 -0
- package/src/knowledge/general/kiss.md +15 -0
- package/src/knowledge/general/least-surprise.md +13 -0
- package/src/knowledge/general/slap.md +29 -0
- package/src/knowledge/general/solid.md +44 -0
- package/src/knowledge/general/tdd.md +76 -0
- package/src/knowledge/general/yagni.md +12 -0
- package/src/knowledge/mobile/android/android-architecture.md +83 -0
- package/src/knowledge/mobile/android/android-platform.md +60 -0
- package/src/knowledge/mobile/android/kotlin-concurrency.md +75 -0
- package/src/knowledge/mobile/android/kotlin-core.md +88 -0
- package/src/knowledge/mobile/flutter/dart-async.md +93 -0
- package/src/knowledge/mobile/flutter/dart-core.md +97 -0
- package/src/knowledge/mobile/flutter/flutter-architecture.md +88 -0
- package/src/knowledge/mobile/flutter/flutter-platform.md +79 -0
- package/src/knowledge/mobile/ios/ios-architecture.md +88 -0
- package/src/knowledge/mobile/ios/ios-platform.md +66 -0
- package/src/knowledge/mobile/ios/swift-concurrency.md +99 -0
- package/src/knowledge/mobile/ios/swift-core.md +79 -0
- package/src/knowledge/planning/architecture-database.md +47 -0
- package/src/knowledge/planning/architecture-patterns.md +64 -0
- package/src/knowledge/planning/architecture-security.md +61 -0
- package/src/knowledge/planning/estimation.md +82 -0
- package/src/knowledge/planning/orchestration.md +70 -0
- package/src/knowledge/planning/prd-quality-gates.md +38 -0
- package/src/knowledge/planning/prd-writing.md +59 -0
- package/src/knowledge/planning/product-principles.md +48 -0
- package/src/knowledge/planning/product-prioritization.md +45 -0
- package/src/knowledge/planning/rfc-quality-gates.md +38 -0
- package/src/knowledge/planning/rfc-writing.md +81 -0
- package/src/knowledge/planning/task-decomposition.md +61 -0
- package/src/knowledge/planning/task-readiness.md +64 -0
- package/src/knowledge/quality/qa-execution.md +55 -0
- package/src/knowledge/quality/qa-reporting.md +71 -0
- package/src/knowledge/quality/test-case-quality.md +61 -0
- package/src/knowledge/quality/test-case-writing.md +76 -0
- package/src/knowledge/quality/testing-strategy.md +70 -0
- package/src/knowledge/quality/testing-types.md +84 -0
- package/src/knowledge/web/backend/api-design.md +74 -0
- package/src/knowledge/web/backend/api-security.md +54 -0
- package/src/knowledge/web/backend/backend-security.md +84 -0
- package/src/knowledge/web/backend/backend-structure.md +78 -0
- package/src/knowledge/web/frontend/frontend-components.md +49 -0
- package/src/knowledge/web/frontend/frontend-performance.md +41 -0
- package/src/knowledge/web/frontend/frontend-state.md +59 -0
- package/src/knowledge/web/frontend/web-accessibility.md +51 -0
- package/src/knowledge/web/frontend/web-performance.md +51 -0
- package/src/knowledge/web/frontend/web-security.md +59 -0
- package/src/templates/prd.md +109 -0
- package/src/templates/rfc.md +156 -0
- package/src/templates/task-breakdown.md +172 -0
- package/src/templates/test-case.md +157 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# hooks/
|
|
2
|
+
|
|
3
|
+
Safety guardrail definitions — the source of truth for dangerous-command blocking across all platforms.
|
|
4
|
+
|
|
5
|
+
The installer reads these files and generates platform-specific hook configs. Edit here, reinstall, and every platform gets the update.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Files
|
|
10
|
+
|
|
11
|
+
| File | Purpose |
|
|
12
|
+
|---|---|
|
|
13
|
+
| `dangerous-commands.json` | Per-platform executable hook configs (Claude Code, Codex, Windsurf) |
|
|
14
|
+
| `dangerous-commands.md` | Text-based safety rules for platforms without executable hooks (Cursor, Copilot) |
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## `*.json` — Executable hook configs
|
|
19
|
+
|
|
20
|
+
Each JSON file describes one safety rule and carries per-platform configurations under a `platforms` key.
|
|
21
|
+
|
|
22
|
+
```json
|
|
23
|
+
{
|
|
24
|
+
"name": "dangerous-commands",
|
|
25
|
+
"description": "Block dangerous shell commands before execution",
|
|
26
|
+
"platforms": {
|
|
27
|
+
"claude": {
|
|
28
|
+
"event": "PreToolUse",
|
|
29
|
+
"matcher": "Bash",
|
|
30
|
+
"hooks": [{ "type": "command", "command": "...", "statusMessage": "..." }]
|
|
31
|
+
},
|
|
32
|
+
"codex": {
|
|
33
|
+
"event": "PreToolUse",
|
|
34
|
+
"matcher": "Bash",
|
|
35
|
+
"hooks": [{ "type": "command", "command": "...", "statusMessage": "..." }]
|
|
36
|
+
},
|
|
37
|
+
"windsurf": {
|
|
38
|
+
"event": "pre_run_command",
|
|
39
|
+
"command": "...",
|
|
40
|
+
"show_output": true
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Platform differences
|
|
47
|
+
|
|
48
|
+
| Platform | Event name | Input key | Block mechanism |
|
|
49
|
+
|---|---|---|---|
|
|
50
|
+
| Claude Code | `PreToolUse` | `tool_input.command` | stdout JSON `{"decision":"block"}` |
|
|
51
|
+
| OpenAI Codex | `PreToolUse` | `tool_input.command` | stdout JSON `{"decision":"block"}` (same engine) |
|
|
52
|
+
| Windsurf | `pre_run_command` | `tool_info.command_line` | exit code `2` |
|
|
53
|
+
|
|
54
|
+
All hooks receive the tool input as JSON on stdin and run as a bash command.
|
|
55
|
+
|
|
56
|
+
### How the installer uses this
|
|
57
|
+
|
|
58
|
+
- `platforms.claude` → merged into `.claude/settings.json` under `hooks.PreToolUse`
|
|
59
|
+
- `platforms.codex` → appended to `.codex/config.toml` under `[[hooks.PreToolUse]]`
|
|
60
|
+
- `platforms.windsurf` → merged into `.windsurf/hooks.json` under `hooks.pre_run_command`
|
|
61
|
+
|
|
62
|
+
Reinstalling is idempotent — the installer removes the previous triples-agentic entry before writing the new one.
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## `*.md` — Text-based safety rules
|
|
67
|
+
|
|
68
|
+
Used for platforms that have no executable hook mechanism. The installer strips the frontmatter and injects the body as an always-applied rule.
|
|
69
|
+
|
|
70
|
+
```markdown
|
|
71
|
+
---
|
|
72
|
+
name: dangerous-commands-safety
|
|
73
|
+
description: Safety guardrails — never run dangerous commands without explicit user confirmation
|
|
74
|
+
platform: all
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Safety Guardrails
|
|
78
|
+
|
|
79
|
+
Never run these commands without explicit user confirmation:
|
|
80
|
+
…
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### How the installer uses this
|
|
84
|
+
|
|
85
|
+
| Platform | Output |
|
|
86
|
+
|---|---|
|
|
87
|
+
| Cursor AI | `.cursor/rules/triples-safety.mdc` with `alwaysApply: true` |
|
|
88
|
+
| GitHub Copilot | `.github/instructions/triples-safety.instructions.md` with `applyTo: "**"` |
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Adding a new safety rule
|
|
93
|
+
|
|
94
|
+
1. Edit the pattern list in the `command` field of `dangerous-commands.json` (all three platform sections).
|
|
95
|
+
2. Add the human-readable description to `dangerous-commands.md`.
|
|
96
|
+
3. Reinstall: `npx triples-agentic`.
|
|
97
|
+
|
|
98
|
+
## Adding a new platform
|
|
99
|
+
|
|
100
|
+
1. Add a `"<platform>"` key under `platforms` in each `.json` hook file.
|
|
101
|
+
2. Add a loader function and settings writer in `src/bin/setup.js`.
|
|
102
|
+
3. Call the settings writer from the platform's `install*` function.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dangerous-commands",
|
|
3
|
+
"description": "Block dangerous shell commands before execution",
|
|
4
|
+
"platforms": {
|
|
5
|
+
"claude": {
|
|
6
|
+
"event": "PreToolUse",
|
|
7
|
+
"matcher": "Bash",
|
|
8
|
+
"hooks": [
|
|
9
|
+
{
|
|
10
|
+
"type": "command",
|
|
11
|
+
"command": "cmd=$(jq -r '.tool_input.command // \"\"'); if echo \"$cmd\" | grep -qiE 'rm[[:space:]]+-rf|rm[[:space:]]+-fr|rm[[:space:]]+(-[a-z]*r[a-z]*[[:space:]]+-[a-z]*f|-[a-z]*f[a-z]*[[:space:]]+-[a-z]*r)|git[[:space:]]+reset[[:space:]]+--hard|git[[:space:]]+push[[:space:]]+(.*--force|-f[[:space:]])|git[[:space:]]+checkout[[:space:]]+--|git[[:space:]]+restore[[:space:]]+\\.|DROP[[:space:]]+(TABLE|DATABASE)|DELETE[[:space:]]+FROM[[:space:]]+[a-zA-Z_]+[[:space:]]*;|fastlane[[:space:]]+(deliver|supply)|gradlew[[:space:]]+.*publishBundle|xcrun[[:space:]]+altool|npm[[:space:]]+publish[[:space:]]|npx[[:space:]]+.*publish[[:space:]]'; then printf '{\"decision\":\"block\",\"reason\":\"Blocked dangerous command — review and run manually if intentional.\"}'; fi",
|
|
12
|
+
"statusMessage": "Checking for dangerous commands..."
|
|
13
|
+
}
|
|
14
|
+
]
|
|
15
|
+
},
|
|
16
|
+
"codex": {
|
|
17
|
+
"event": "PreToolUse",
|
|
18
|
+
"matcher": "Bash",
|
|
19
|
+
"hooks": [
|
|
20
|
+
{
|
|
21
|
+
"type": "command",
|
|
22
|
+
"command": "cmd=$(jq -r '.tool_input.command // \"\"'); if echo \"$cmd\" | grep -qiE 'rm[[:space:]]+-rf|rm[[:space:]]+-fr|rm[[:space:]]+(-[a-z]*r[a-z]*[[:space:]]+-[a-z]*f|-[a-z]*f[a-z]*[[:space:]]+-[a-z]*r)|git[[:space:]]+reset[[:space:]]+--hard|git[[:space:]]+push[[:space:]]+(.*--force|-f[[:space:]])|git[[:space:]]+checkout[[:space:]]+--|git[[:space:]]+restore[[:space:]]+\\.|DROP[[:space:]]+(TABLE|DATABASE)|DELETE[[:space:]]+FROM[[:space:]]+[a-zA-Z_]+[[:space:]]*;|fastlane[[:space:]]+(deliver|supply)|gradlew[[:space:]]+.*publishBundle|xcrun[[:space:]]+altool|npm[[:space:]]+publish[[:space:]]|npx[[:space:]]+.*publish[[:space:]]'; then printf '{\"decision\":\"block\",\"reason\":\"Blocked dangerous command — review and run manually if intentional.\"}'; fi",
|
|
23
|
+
"statusMessage": "Checking for dangerous commands..."
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
},
|
|
27
|
+
"windsurf": {
|
|
28
|
+
"event": "pre_run_command",
|
|
29
|
+
"command": "cmd=$(jq -r '.tool_info.command_line // \"\"' 2>/dev/null || echo \"\"); if echo \"$cmd\" | grep -qiE 'rm[[:space:]]+-rf|rm[[:space:]]+-fr|rm[[:space:]]+(-[a-z]*r[a-z]*[[:space:]]+-[a-z]*f|-[a-z]*f[a-z]*[[:space:]]+-[a-z]*r)|git[[:space:]]+reset[[:space:]]+--hard|git[[:space:]]+push[[:space:]]+(.*--force|-f[[:space:]])|git[[:space:]]+checkout[[:space:]]+--|git[[:space:]]+restore[[:space:]]+\\.|DROP[[:space:]]+(TABLE|DATABASE)|DELETE[[:space:]]+FROM[[:space:]]+[a-zA-Z_]+[[:space:]]*;|fastlane[[:space:]]+(deliver|supply)|gradlew[[:space:]]+.*publishBundle|xcrun[[:space:]]+altool|npm[[:space:]]+publish[[:space:]]|npx[[:space:]]+.*publish[[:space:]]'; then printf 'Blocked dangerous command — review and run manually if intentional.\\n' >&2; exit 2; fi",
|
|
30
|
+
"show_output": true
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dangerous-commands-safety
|
|
3
|
+
description: Safety guardrails — never run dangerous commands without explicit user confirmation
|
|
4
|
+
platform: all
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Safety Guardrails
|
|
8
|
+
|
|
9
|
+
Never run these commands without explicit user confirmation:
|
|
10
|
+
|
|
11
|
+
- **Filesystem**: `rm -rf`, `rm -fr`, any recursive force delete
|
|
12
|
+
- **Git destructive**: `git reset --hard`, `git checkout --`, `git restore .`
|
|
13
|
+
- **Git push force**: `git push --force`, `git push -f`
|
|
14
|
+
- **SQL destructive**: `DROP TABLE`, `DROP DATABASE`, `DELETE FROM <table>;`
|
|
15
|
+
- **Store publish**: `fastlane deliver`, `fastlane supply`, `gradlew publishBundle`, `xcrun altool`
|
|
16
|
+
- **Package publish**: `npm publish`, `npx ... publish`
|
|
17
|
+
|
|
18
|
+
Stop and ask the user for explicit confirmation before running any of the above.
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# knowledge/
|
|
2
|
+
|
|
3
|
+
Domain expertise loaded by agents at runtime. Pure reference `.md` files — no trigger logic, no skills framework.
|
|
4
|
+
|
|
5
|
+
Agents declare which files to load via `<!-- knowledge: ... -->` metadata in their agent definition. The AI reads and applies these files as context when it activates.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## File format
|
|
10
|
+
|
|
11
|
+
Every knowledge file has YAML frontmatter followed by markdown content:
|
|
12
|
+
|
|
13
|
+
```markdown
|
|
14
|
+
---
|
|
15
|
+
name: api-design
|
|
16
|
+
description: REST and GraphQL API design conventions — URL structure, versioning, pagination, filtering, and documentation
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
# API Design
|
|
20
|
+
|
|
21
|
+
## REST URL Conventions
|
|
22
|
+
…
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
| Field | Purpose |
|
|
26
|
+
|---|---|
|
|
27
|
+
| `name` | Slug used as the skill name when installed to Claude Code |
|
|
28
|
+
| `description` | One-line summary shown in the install banner and used as the skill trigger description |
|
|
29
|
+
|
|
30
|
+
The content is plain markdown — headings, bullet lists, code blocks. Write it as a reference document, not a tutorial.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Directory structure
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
knowledge/
|
|
38
|
+
├── general/ Coding principles — loaded by all developer agents
|
|
39
|
+
│ ├── dry.md Don't Repeat Yourself
|
|
40
|
+
│ ├── kiss.md Keep It Simple
|
|
41
|
+
│ ├── yagni.md You Aren't Gonna Need It
|
|
42
|
+
│ ├── solid.md SOLID principles
|
|
43
|
+
│ ├── slap.md Single Level of Abstraction
|
|
44
|
+
│ ├── tdd.md Test-Driven Development
|
|
45
|
+
│ ├── fail-fast.md Validate at boundaries, surface errors early
|
|
46
|
+
│ ├── least-surprise.md Code behaves as readers expect
|
|
47
|
+
│ ├── boy-scout-rule.md Leave code cleaner than you found it
|
|
48
|
+
│ └── composition-over-inheritance.md
|
|
49
|
+
│
|
|
50
|
+
├── planning/ Loaded by SeoYeon, JiWoo, YooYeon, NaKyoung
|
|
51
|
+
│ ├── orchestration.md Workflow sequencing, delegation, escalation
|
|
52
|
+
│ ├── prd-writing.md PRD structure, writing standards, anti-patterns
|
|
53
|
+
│ ├── prd-quality-gates.md PRD review checklist
|
|
54
|
+
│ ├── product-principles.md PM principles, prioritization frameworks
|
|
55
|
+
│ ├── product-prioritization.md
|
|
56
|
+
│ ├── rfc-writing.md RFC structure, ADR format, anti-patterns
|
|
57
|
+
│ ├── rfc-quality-gates.md RFC review checklist
|
|
58
|
+
│ ├── architecture-patterns.md System design, database selection, scalability
|
|
59
|
+
│ ├── architecture-database.md Database design and selection criteria
|
|
60
|
+
│ ├── architecture-security.md Security fundamentals for system design
|
|
61
|
+
│ ├── task-decomposition.md Task hierarchy, story mapping, readiness checklist
|
|
62
|
+
│ ├── task-readiness.md Task readiness criteria
|
|
63
|
+
│ └── estimation.md Fibonacci points, time estimation, planning poker
|
|
64
|
+
│
|
|
65
|
+
├── web/
|
|
66
|
+
│ ├── frontend/ Loaded by YuBin
|
|
67
|
+
│ │ ├── frontend-components.md React/Vue/Angular patterns, component design
|
|
68
|
+
│ │ ├── frontend-state.md State management patterns
|
|
69
|
+
│ │ ├── frontend-performance.md Bundle size, rendering, lazy loading
|
|
70
|
+
│ │ ├── web-accessibility.md WCAG 2.1 AA, semantic HTML, ARIA
|
|
71
|
+
│ │ ├── web-performance.md LCP, CLS, Core Web Vitals
|
|
72
|
+
│ │ └── web-security.md CSP, XSS prevention, secure headers
|
|
73
|
+
│ └── backend/ Loaded by Kaede (api-design.md also loaded by Kotone)
|
|
74
|
+
│ ├── backend-structure.md Project layout, layered architecture
|
|
75
|
+
│ ├── backend-security.md Input validation, parameterized queries, secrets
|
|
76
|
+
│ ├── api-design.md REST/GraphQL conventions, versioning, pagination
|
|
77
|
+
│ └── api-security.md Auth, rate limiting, OWASP API top 10
|
|
78
|
+
│
|
|
79
|
+
├── mobile/
|
|
80
|
+
│ ├── android/ Loaded by YeonJi
|
|
81
|
+
│ │ ├── android-architecture.md MVVM, Compose, Hilt, Navigation, Material 3
|
|
82
|
+
│ │ ├── android-platform.md Play Store, permissions, lifecycle
|
|
83
|
+
│ │ ├── kotlin-core.md Null safety, sealed classes, extension functions
|
|
84
|
+
│ │ └── kotlin-concurrency.md Coroutines, Flow, structured concurrency
|
|
85
|
+
│ ├── ios/ Loaded by SoHyun
|
|
86
|
+
│ │ ├── ios-architecture.md SwiftUI, MVVM, NavigationStack, Apple HIG
|
|
87
|
+
│ │ ├── ios-platform.md App Store, privacy manifest, safe areas
|
|
88
|
+
│ │ ├── swift-core.md Optionals, value types, async/await, protocols
|
|
89
|
+
│ │ └── swift-concurrency.md actors, async/await, Task, structured concurrency
|
|
90
|
+
│ └── flutter/ Loaded by Kotone
|
|
91
|
+
│ ├── flutter-architecture.md Riverpod, GoRouter, Material 3, widget design
|
|
92
|
+
│ ├── flutter-platform.md Play Store + App Store, platform channels
|
|
93
|
+
│ ├── dart-core.md Null safety, collections, classes, mixins
|
|
94
|
+
│ └── dart-async.md async/await, Future, Stream, Isolate
|
|
95
|
+
│
|
|
96
|
+
└── quality/ Loaded by Lynn and ShiOn
|
|
97
|
+
├── testing-strategy.md Testing pyramid, shift-left, anti-patterns
|
|
98
|
+
├── testing-types.md Unit, integration, E2E, exploratory definitions
|
|
99
|
+
├── test-case-writing.md Test case structure, priority levels, quality gates
|
|
100
|
+
├── test-case-quality.md Quality checklist for test case review
|
|
101
|
+
├── qa-execution.md Execution process, bug report format, go/no-go criteria
|
|
102
|
+
└── qa-reporting.md QA report structure, metrics, defect classification
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## How knowledge gets installed
|
|
108
|
+
|
|
109
|
+
The installer copies each knowledge file to the target platform directory alongside the agent files:
|
|
110
|
+
|
|
111
|
+
| Platform | Installed path |
|
|
112
|
+
|---|---|
|
|
113
|
+
| Claude Code | `.claude/skills/knowledge/<group>/<file>.md` (existing frontmatter kept) |
|
|
114
|
+
| Cursor AI | `.cursor/rules/knowledge/<group>/<file>.mdc` (frontmatter rewritten for Cursor) |
|
|
115
|
+
| GitHub Copilot | `.github/instructions/knowledge/<group>/<file>.instructions.md` |
|
|
116
|
+
| OpenAI Codex | Inline section in `AGENTS.md` (frontmatter stripped) |
|
|
117
|
+
| Windsurf | Inline section in `.windsurfrules` (frontmatter stripped) |
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## Adding a knowledge file
|
|
122
|
+
|
|
123
|
+
1. Create a `.md` file in the appropriate subdirectory.
|
|
124
|
+
2. Add frontmatter with `name` and `description`.
|
|
125
|
+
3. Write the content as a reference document.
|
|
126
|
+
4. Reference it in the agent's `<!-- knowledge: ... -->` metadata and add a line to its `## Knowledge` section.
|
|
127
|
+
5. Reinstall: `npx triples-agentic`.
|
|
128
|
+
|
|
129
|
+
Knowledge files are **read-only reference** — they describe what to know, not what to do. Procedural steps belong in agent `## Skills` sections.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: boy-scout-rule
|
|
3
|
+
description: Boy Scout Rule — leave the code cleaner than you found it through small, incremental improvements
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Boy Scout Rule
|
|
7
|
+
|
|
8
|
+
Leave the code cleaner than you found it.
|
|
9
|
+
|
|
10
|
+
- If you touch a file, fix the obvious issues nearby (rename a confusing variable, remove a dead comment)
|
|
11
|
+
- Do not let this justify scope creep — small, incremental improvements only
|
|
12
|
+
- Do not refactor code you do not understand yet
|
|
13
|
+
- A codebase that improves slightly with every PR never needs a big rewrite
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: composition-over-inheritance
|
|
3
|
+
description: Favor composing behavior from small focused pieces over deep inheritance hierarchies
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Composition Over Inheritance
|
|
7
|
+
|
|
8
|
+
Favor composing behavior from small, focused pieces over deep inheritance hierarchies.
|
|
9
|
+
|
|
10
|
+
- Inheritance couples subclass to superclass implementation details
|
|
11
|
+
- Composition lets you swap or combine behaviors at runtime
|
|
12
|
+
- Prefer interfaces/protocols + composition when multiple behaviors are needed
|
|
13
|
+
- Deep inheritance trees are hard to reason about — changes at the top ripple unpredictably
|
|
14
|
+
- A class that inherits from more than one level of hierarchy is a warning sign
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dry
|
|
3
|
+
description: DRY (Don't Repeat Yourself) — every piece of knowledge must have a single, unambiguous representation in the system
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# DRY — Don't Repeat Yourself
|
|
7
|
+
|
|
8
|
+
Every piece of knowledge must have a single, unambiguous representation in the system.
|
|
9
|
+
|
|
10
|
+
- Extract repeated logic into a named function, class, or module
|
|
11
|
+
- Repeated data belongs in a constant or configuration, not scattered literals
|
|
12
|
+
- Duplication of intent is worse than duplication of text — two functions that do the same thing but look different are the hardest to catch
|
|
13
|
+
|
|
14
|
+
**When NOT to apply:** Premature abstraction to avoid three similar-looking lines produces worse code than the duplication. Wait for a third repetition before extracting. Deduplication that crosses wrong boundaries creates tight coupling.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: fail-fast
|
|
3
|
+
description: Fail Fast — detect and surface errors as early and loudly as possible
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Fail Fast
|
|
7
|
+
|
|
8
|
+
Detect and surface errors as early and loudly as possible.
|
|
9
|
+
|
|
10
|
+
- Validate inputs at system boundaries, not deep inside business logic
|
|
11
|
+
- Return or throw immediately on invalid state — don't carry partial state forward
|
|
12
|
+
- Assertions and guards at function entry are cheaper than debugging corrupted state later
|
|
13
|
+
- An error that surfaces at the point of cause is 10x easier to diagnose than one that surfaces two call frames later
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: kiss
|
|
3
|
+
description: KISS (Keep It Simple, Stupid) — the simplest solution that works is correct; complexity must justify itself
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# KISS — Keep It Simple, Stupid
|
|
7
|
+
|
|
8
|
+
The simplest solution that works is correct. Complexity must justify itself.
|
|
9
|
+
|
|
10
|
+
- Prefer readable, obvious code over clever one-liners
|
|
11
|
+
- Avoid over-engineering for hypothetical future requirements
|
|
12
|
+
- If you need a comment to explain what the code does, the code is probably too complex
|
|
13
|
+
- Fewer moving parts = fewer failure modes
|
|
14
|
+
|
|
15
|
+
**Ask before adding complexity:** "Will this system actually need this in the next 3 months?" If no, don't build it.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: least-surprise
|
|
3
|
+
description: Principle of Least Surprise — code should behave in the way a reader would expect
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Principle of Least Surprise
|
|
7
|
+
|
|
8
|
+
Code should behave in the way a reader would expect.
|
|
9
|
+
|
|
10
|
+
- Functions named `getUser` should not modify state
|
|
11
|
+
- A method that returns a list should never return `null` — return an empty list
|
|
12
|
+
- Avoid side effects in places where callers don't expect them (constructors, getters, equality checks)
|
|
13
|
+
- Consistent naming conventions matter: if `save()` persists to DB everywhere, it should do so everywhere
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: slap
|
|
3
|
+
description: SLAP (Single Level of Abstraction Principle) — each function should operate at a single level of abstraction
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# SLAP — Single Level of Abstraction Principle
|
|
7
|
+
|
|
8
|
+
Each function should operate at a single level of abstraction.
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
// Bad — mixes high-level orchestration with low-level detail
|
|
12
|
+
function processOrder(order) {
|
|
13
|
+
validateOrder(order);
|
|
14
|
+
const sql = `INSERT INTO orders (id, total) VALUES (${order.id}, ${order.total})`;
|
|
15
|
+
db.execute(sql);
|
|
16
|
+
sendEmail(order.user.email, 'Order confirmed');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Good — consistent abstraction level
|
|
20
|
+
function processOrder(order) {
|
|
21
|
+
validateOrder(order);
|
|
22
|
+
saveOrder(order);
|
|
23
|
+
notifyUser(order);
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
- If one line calls a named function and the next line contains raw SQL or DOM manipulation, the abstraction levels are mismatched
|
|
28
|
+
- Extract lower-level details into well-named helpers to restore consistency
|
|
29
|
+
- Consistent abstraction levels make a function readable top-to-bottom without context switches
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: solid
|
|
3
|
+
description: SOLID principles for object-oriented design — SRP, OCP, LSP, ISP, DIP
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# SOLID Principles (Object-Oriented Design)
|
|
7
|
+
|
|
8
|
+
## S — Single Responsibility Principle
|
|
9
|
+
A class (or module, or function) should have one reason to change.
|
|
10
|
+
|
|
11
|
+
- A class that handles both business logic and database access has two reasons to change
|
|
12
|
+
- Split responsibilities along the axis of change: what causes this to need updating?
|
|
13
|
+
- Small, focused units are easier to test, reuse, and rename
|
|
14
|
+
|
|
15
|
+
## O — Open/Closed Principle
|
|
16
|
+
Open for extension, closed for modification.
|
|
17
|
+
|
|
18
|
+
- Add new behavior by adding new code, not by editing existing code
|
|
19
|
+
- Use polymorphism, strategy pattern, or composition to extend behavior
|
|
20
|
+
- Modifying existing code risks breaking existing behavior; adding new code does not
|
|
21
|
+
|
|
22
|
+
## L — Liskov Substitution Principle
|
|
23
|
+
Subtypes must be substitutable for their base types without breaking the program.
|
|
24
|
+
|
|
25
|
+
- If `class B extends A`, then anywhere `A` is used, `B` must work correctly
|
|
26
|
+
- Violations: a subclass that throws on a method the base class supports, or returns a narrower result
|
|
27
|
+
- If you find yourself overriding a method to do nothing or throw, the inheritance hierarchy is wrong
|
|
28
|
+
|
|
29
|
+
## I — Interface Segregation Principle
|
|
30
|
+
No client should be forced to depend on methods it does not use.
|
|
31
|
+
|
|
32
|
+
- Prefer several small, focused interfaces over one large general-purpose interface
|
|
33
|
+
- A class that implements a large interface but only needs 2 of 10 methods is a sign the interface should be split
|
|
34
|
+
- Applies to function parameters too: pass only what the callee actually needs
|
|
35
|
+
|
|
36
|
+
## D — Dependency Inversion Principle
|
|
37
|
+
High-level modules should not depend on low-level modules. Both should depend on abstractions.
|
|
38
|
+
|
|
39
|
+
- Business logic should not import a specific database library directly — it should depend on a repository interface
|
|
40
|
+
- Makes high-level policy independent of implementation details
|
|
41
|
+
- Enables swapping implementations (e.g., real DB vs. in-memory for tests) without changing business logic
|
|
42
|
+
|
|
43
|
+
## When to apply SOLID
|
|
44
|
+
SOLID is most valuable at module and service boundaries. Inside a small, private function, rigid SOLID application adds noise without benefit. Don't add abstractions until you have two concrete use cases.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: tdd
|
|
3
|
+
description: Test-Driven Development (TDD) — write a failing test first, then write the minimum code to make it pass, then refactor
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# TDD — Test-Driven Development
|
|
7
|
+
|
|
8
|
+
Write a failing test before writing any production code. Let the test drive the design.
|
|
9
|
+
|
|
10
|
+
## The Red-Green-Refactor Cycle
|
|
11
|
+
|
|
12
|
+
1. **Red** — write a test that describes the desired behavior. Run it. It must fail.
|
|
13
|
+
2. **Green** — write the minimum code to make the test pass. No more.
|
|
14
|
+
3. **Refactor** — clean up the code without changing behavior. Tests stay green.
|
|
15
|
+
|
|
16
|
+
Repeat for every new behavior.
|
|
17
|
+
|
|
18
|
+
## Rules
|
|
19
|
+
|
|
20
|
+
- Never write production code without a failing test that justifies it
|
|
21
|
+
- Write only enough production code to make the current failing test pass
|
|
22
|
+
- Never refactor while red — only clean up when tests are passing
|
|
23
|
+
- One failing test at a time: don't write the next test until the current one is green
|
|
24
|
+
|
|
25
|
+
## Why TDD produces better design
|
|
26
|
+
|
|
27
|
+
- Forces you to think about the interface before the implementation
|
|
28
|
+
- Code that is hard to test is a signal of tight coupling or unclear responsibilities — TDD surfaces this early
|
|
29
|
+
- The test suite becomes a living specification of what the system does
|
|
30
|
+
- Refactoring is safe when every behavior is covered — you move fast without breaking things
|
|
31
|
+
|
|
32
|
+
## What a good TDD test looks like
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
// Arrange — set up the inputs and context
|
|
36
|
+
// Act — call the unit under test
|
|
37
|
+
// Assert — verify the outcome
|
|
38
|
+
|
|
39
|
+
test('calculates order total with discount applied', () => {
|
|
40
|
+
const order = new Order([{ price: 100, qty: 2 }]);
|
|
41
|
+
|
|
42
|
+
const total = order.totalWithDiscount(0.1);
|
|
43
|
+
|
|
44
|
+
expect(total).toBe(180);
|
|
45
|
+
});
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
- One concept per test
|
|
49
|
+
- Test name describes the behavior, not the implementation ("returns 180" not "calls applyDiscount")
|
|
50
|
+
- No logic in tests (no if/for) — tests should be trivially readable
|
|
51
|
+
- Tests are isolated: no shared mutable state between tests
|
|
52
|
+
|
|
53
|
+
## TDD scope
|
|
54
|
+
|
|
55
|
+
| Level | What to TDD | Examples |
|
|
56
|
+
|---|---|---|
|
|
57
|
+
| Unit | Business logic, calculations, transformations | Services, utilities, domain models |
|
|
58
|
+
| Integration | Interactions between components | Repository + DB, API handler + service |
|
|
59
|
+
| E2E | Critical user flows | Login, checkout, core happy path |
|
|
60
|
+
|
|
61
|
+
TDD is most valuable at the unit and integration levels. E2E tests are expensive to write first — write them after the feature is built to lock in the happy path.
|
|
62
|
+
|
|
63
|
+
## When NOT to apply TDD strictly
|
|
64
|
+
|
|
65
|
+
- **Exploratory / spike code** — when you don't yet know the shape of the solution, write the spike first, then delete it and TDD the real implementation
|
|
66
|
+
- **UI layout and styling** — visual behavior is better verified by snapshot or manual review
|
|
67
|
+
- **Third-party integrations** — write tests against your wrapper/adapter, not against the external API itself
|
|
68
|
+
|
|
69
|
+
## TDD and refactoring
|
|
70
|
+
|
|
71
|
+
The refactor step is not optional. Green tests without refactoring accumulates design debt. After each green:
|
|
72
|
+
|
|
73
|
+
- Remove duplication (DRY)
|
|
74
|
+
- Rename for clarity
|
|
75
|
+
- Extract if a function is doing more than one thing (SRP)
|
|
76
|
+
- The test suite must still be fully green after every change
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: yagni
|
|
3
|
+
description: YAGNI (You Aren't Gonna Need It) — do not implement something until it is actually required
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# YAGNI — You Aren't Gonna Need It
|
|
7
|
+
|
|
8
|
+
Do not implement something until it is actually required.
|
|
9
|
+
|
|
10
|
+
- No speculative features, hooks for future use, or "just in case" parameters
|
|
11
|
+
- Extension points and abstractions added before they are needed almost always get the shape wrong
|
|
12
|
+
- Dead code is a maintenance liability — it still needs to be read, reasoned about, and updated
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: android-architecture
|
|
3
|
+
description: Android MVVM + Clean Architecture, Jetpack Compose patterns, Hilt DI, and Navigation Compose
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Android Architecture
|
|
7
|
+
|
|
8
|
+
## Architecture Pattern: MVVM + Clean Architecture
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
UI Layer (Composable)
|
|
12
|
+
↕ StateFlow / collect
|
|
13
|
+
ViewModel (state holder, no Android dependencies)
|
|
14
|
+
↕ suspend functions / Flow
|
|
15
|
+
Repository (single data access layer)
|
|
16
|
+
↕ API / Room / DataStore
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Jetpack Compose Rules
|
|
20
|
+
|
|
21
|
+
- Composables are stateless by default — pass state down, events up
|
|
22
|
+
- Use `remember` for UI-only ephemeral state (not business state)
|
|
23
|
+
- Hoist state to the lowest common ancestor that needs it
|
|
24
|
+
- Break large composables into smaller ones: if it doesn't fit on one screen, split it
|
|
25
|
+
|
|
26
|
+
```kotlin
|
|
27
|
+
// Correct: stateless composable + hoisted state in ViewModel
|
|
28
|
+
@Composable
|
|
29
|
+
fun LoginScreen(
|
|
30
|
+
uiState: LoginUiState,
|
|
31
|
+
onEmailChanged: (String) -> Unit,
|
|
32
|
+
onLoginClick: () -> Unit,
|
|
33
|
+
) { ... }
|
|
34
|
+
|
|
35
|
+
// Only at screen entry points (top-level routes)
|
|
36
|
+
@Composable
|
|
37
|
+
fun LoginRoute(viewModel: LoginViewModel = hiltViewModel()) {
|
|
38
|
+
LoginScreen(
|
|
39
|
+
uiState = viewModel.uiState.collectAsState().value,
|
|
40
|
+
onEmailChanged = viewModel::onEmailChanged,
|
|
41
|
+
onLoginClick = viewModel::login,
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Dependency Injection — Hilt
|
|
47
|
+
|
|
48
|
+
- `@HiltAndroidApp` on Application class
|
|
49
|
+
- `@AndroidEntryPoint` on Activities/Fragments that use injection
|
|
50
|
+
- `@HiltViewModel` for ViewModels
|
|
51
|
+
- Scopes: `@Singleton` for app-wide, `@ActivityScoped` for per-screen
|
|
52
|
+
|
|
53
|
+
## Navigation — Navigation Compose
|
|
54
|
+
|
|
55
|
+
```kotlin
|
|
56
|
+
// Define routes as a sealed hierarchy
|
|
57
|
+
sealed class Screen(val route: String) {
|
|
58
|
+
object Login : Screen("login")
|
|
59
|
+
data class Profile(val userId: String) : Screen("profile/{userId}")
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// NavHost setup
|
|
63
|
+
NavHost(navController, startDestination = Screen.Login.route) {
|
|
64
|
+
composable(Screen.Login.route) { LoginRoute(navController) }
|
|
65
|
+
composable("profile/{userId}") { backStackEntry ->
|
|
66
|
+
ProfileRoute(userId = backStackEntry.arguments?.getString("userId")!!)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Navigate from ViewModel using a sealed event/effect — never hold NavController in ViewModel.
|
|
72
|
+
|
|
73
|
+
## Network — Retrofit + OkHttp
|
|
74
|
+
|
|
75
|
+
```kotlin
|
|
76
|
+
@GET("users/{id}")
|
|
77
|
+
suspend fun getUser(@Path("id") id: String): UserDto
|
|
78
|
+
|
|
79
|
+
// Add logging interceptor for debug builds only
|
|
80
|
+
if (BuildConfig.DEBUG) {
|
|
81
|
+
addInterceptor(HttpLoggingInterceptor().apply { level = BODY })
|
|
82
|
+
}
|
|
83
|
+
```
|