opencodekit 0.6.7 → 0.7.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/dist/index.js +654 -651
- package/dist/template/.opencode/AGENTS.md +56 -11
- package/dist/template/.opencode/README.md +18 -16
- package/dist/template/.opencode/command/accessibility-check.md +1 -1
- package/dist/template/.opencode/command/analyze-mockup.md +1 -1
- package/dist/template/.opencode/command/analyze-project.md +2 -0
- package/dist/template/.opencode/command/brainstorm.md +1 -1
- package/dist/template/.opencode/command/commit.md +1 -1
- package/dist/template/.opencode/command/create.md +9 -0
- package/dist/template/.opencode/command/design-audit.md +1 -1
- package/dist/template/.opencode/command/design.md +1 -1
- package/dist/template/.opencode/command/finish.md +17 -0
- package/dist/template/.opencode/command/fix-ci.md +4 -0
- package/dist/template/.opencode/command/fix-types.md +2 -0
- package/dist/template/.opencode/command/fix-ui.md +1 -1
- package/dist/template/.opencode/command/fix.md +1 -1
- package/dist/template/.opencode/command/handoff.md +2 -0
- package/dist/template/.opencode/command/implement.md +31 -1
- package/dist/template/.opencode/command/import-plan.md +2 -0
- package/dist/template/.opencode/command/integration-test.md +6 -2
- package/dist/template/.opencode/command/new-feature.md +2 -0
- package/dist/template/.opencode/command/plan.md +2 -0
- package/dist/template/.opencode/command/pr.md +2 -0
- package/dist/template/.opencode/command/research-and-implement.md +1 -1
- package/dist/template/.opencode/command/research-ui.md +1 -1
- package/dist/template/.opencode/command/resume.md +2 -0
- package/dist/template/.opencode/command/revert-feature.md +2 -0
- package/dist/template/.opencode/command/review-codebase.md +1 -1
- package/dist/template/.opencode/command/skill-create.md +4 -4
- package/dist/template/.opencode/command/skill-optimize.md +4 -4
- package/dist/template/.opencode/command/ui-review.md +2 -2
- package/dist/template/.opencode/opencode.json +489 -491
- package/dist/template/.opencode/package.json +20 -20
- package/dist/template/.opencode/skill/brainstorming/SKILL.md +2 -2
- package/dist/template/.opencode/skill/executing-plans/SKILL.md +1 -1
- package/dist/template/.opencode/skill/sharing-skills/SKILL.md +13 -4
- package/dist/template/.opencode/skill/subagent-driven-development/SKILL.md +1 -1
- package/dist/template/.opencode/skill/systematic-debugging/SKILL.md +2 -2
- package/dist/template/.opencode/skill/using-git-worktrees/SKILL.md +27 -18
- package/dist/template/.opencode/skill/{using-superpowers → using-skills}/SKILL.md +6 -3
- package/dist/template/.opencode/skill/writing-plans/SKILL.md +3 -3
- package/dist/template/.opencode/skill/writing-skills/SKILL.md +2 -2
- package/package.json +2 -1
- package/dist/template/.opencode/memory/handoffs/2025-12-27T103000Z.md +0 -76
- package/dist/template/.opencode/plugin/skill.ts +0 -275
- package/dist/template/.opencode/skill/systematic-debugging/CREATION-LOG.md +0 -119
- package/dist/template/.opencode/skill/systematic-debugging/test-academic.md +0 -14
- package/dist/template/.opencode/skill/systematic-debugging/test-pressure-1.md +0 -58
- package/dist/template/.opencode/skill/systematic-debugging/test-pressure-2.md +0 -68
- package/dist/template/.opencode/skill/systematic-debugging/test-pressure-3.md +0 -69
- package/dist/template/.opencode/skill/testing-skills-with-subagents/examples/CLAUDE_MD_TESTING.md +0 -189
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
1. Security constraints (always first)
|
|
6
6
|
2. Anti-hallucination rule (overrides all except security)
|
|
7
7
|
3. Delegation rules (check before tool calls)
|
|
8
|
-
4. Skills check (`
|
|
8
|
+
4. Skills check (native `skill` tool)
|
|
9
9
|
5. User explicit requests
|
|
10
10
|
6. Base prompt behaviors
|
|
11
11
|
7. Global rules (this file)
|
|
@@ -302,9 +302,58 @@ Use all three:
|
|
|
302
302
|
|
|
303
303
|
**Philosophy**: Beads is execution, not planning. Plan elsewhere, track in Beads.
|
|
304
304
|
|
|
305
|
+
## Beads Village (Multi-Agent Coordination)
|
|
306
|
+
|
|
307
|
+
MCP server for task coordination and file locking between agents.
|
|
308
|
+
|
|
309
|
+
### When to Use
|
|
310
|
+
|
|
311
|
+
- **Multi-agent work**: Multiple agents on same codebase
|
|
312
|
+
- **File conflict prevention**: Reserve files before editing
|
|
313
|
+
- **Cross-workspace coordination**: FE/BE/Mobile agents communicating
|
|
314
|
+
|
|
315
|
+
### Core Workflow
|
|
316
|
+
|
|
317
|
+
```
|
|
318
|
+
init() → claim() → reserve(paths) → [work] → done(id, msg) → RESTART
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
### Key Tools
|
|
322
|
+
|
|
323
|
+
**Session Management**
|
|
324
|
+
|
|
325
|
+
Start every session by calling `init` with your team name and role. This registers you in the workspace and enables role-based task filtering. For example, `init(team="project", role="fe")` joins as a frontend agent.
|
|
326
|
+
|
|
327
|
+
Check workspace state with `status(include_agents=true)` to see active agents, file locks, and pending messages.
|
|
328
|
+
|
|
329
|
+
**Task Operations**
|
|
330
|
+
|
|
331
|
+
Call `claim` to get the next ready task assigned to your role. It auto-filters based on task tags matching your role.
|
|
332
|
+
|
|
333
|
+
When work is complete, call `done(id="bd-42", msg="Implemented feature X")` to close the task and notify other agents. After `done`, restart your session for a fresh context.
|
|
334
|
+
|
|
335
|
+
**File Reservations**
|
|
336
|
+
|
|
337
|
+
Before editing files, call `reserve(paths=["src/auth.ts"])` to lock them. This prevents other agents from modifying the same files. Call `release` when finished to unlock.
|
|
338
|
+
|
|
339
|
+
**Messaging**
|
|
340
|
+
|
|
341
|
+
Send messages with `msg(subj="API Ready", global=true, to="all")` for cross-workspace announcements. Check incoming messages with `inbox(unread=true)`.
|
|
342
|
+
|
|
343
|
+
### Integration with Commands
|
|
344
|
+
|
|
345
|
+
Use `/create` for the full spec workflow instead of the Village `add` tool. When implementing, `claim` gets your task and `reserve` locks files - Village handles the coordination while your `/implement` command handles the actual work. When finishing, `done` syncs state and notifies other agents.
|
|
346
|
+
|
|
347
|
+
### Rules
|
|
348
|
+
|
|
349
|
+
- **Always `init()` first** in any session using Village tools
|
|
350
|
+
- **Reserve before edit** to prevent conflicts
|
|
351
|
+
- **One task per session** - restart after `done()`
|
|
352
|
+
- **Use `msg(global=true)`** for cross-workspace announcements
|
|
353
|
+
|
|
305
354
|
## Skills System
|
|
306
355
|
|
|
307
|
-
|
|
356
|
+
OpenCode has a native `skill` tool that auto-discovers skills from `.opencode/skill/` and `~/.config/opencode/skill/`. Use `skill({ name: "skill-name" })` when:
|
|
308
357
|
|
|
309
358
|
- Creating something new → `brainstorming`
|
|
310
359
|
- Bug or unexpected behavior → `systematic-debugging`
|
|
@@ -321,16 +370,12 @@ Use `find_skills` → `use_skill` when:
|
|
|
321
370
|
|
|
322
371
|
Skip for simple questions, quick edits, or conversations.
|
|
323
372
|
|
|
324
|
-
###
|
|
325
|
-
|
|
326
|
-
Skills consume context. Manage them actively:
|
|
327
|
-
|
|
328
|
-
1. **Load on-demand**: Only load skills when starting relevant work
|
|
329
|
-
2. **Read linked files lazily**: Don't load all skill references immediately—read only when needed
|
|
330
|
-
3. **Unload after completion**: When task completes, skill context is no longer needed
|
|
331
|
-
4. **One skill at a time**: Avoid loading multiple skills unless task requires it
|
|
373
|
+
### How It Works
|
|
332
374
|
|
|
333
|
-
|
|
375
|
+
1. Available skills are listed in the `skill` tool description (auto-discovered)
|
|
376
|
+
2. Load a skill: `skill({ name: "brainstorming" })`
|
|
377
|
+
3. Skills consume context - load on-demand, one at a time
|
|
378
|
+
4. Skill permissions can be configured in `opencode.json` (`allow`/`deny`/`ask`)
|
|
334
379
|
|
|
335
380
|
## Core Constraints
|
|
336
381
|
|
|
@@ -41,7 +41,7 @@ opencode
|
|
|
41
41
|
│
|
|
42
42
|
├── agent/ # Custom agents (5 total)
|
|
43
43
|
├── command/ # Custom commands (26 workflows)
|
|
44
|
-
├──
|
|
44
|
+
├── skill/ # Domain expertise (27 skills)
|
|
45
45
|
├── tool/ # Custom MCP tools (memory-*, observation, ast-grep)
|
|
46
46
|
├── plugin/ # Background plugins (enforcer, compactor, truncator)
|
|
47
47
|
└── memory/ # Persistent context
|
|
@@ -105,22 +105,23 @@ GOOGLE_APPLICATION_CREDENTIALS=/path/to/key.json
|
|
|
105
105
|
|
|
106
106
|
- `/commit` - Intelligent git commits
|
|
107
107
|
- `/pr` - Create pull requests
|
|
108
|
-
- `/design` - Thoughtful design with brainstorming
|
|
109
|
-
- `/fix` - Systematic debugging
|
|
110
|
-
- `/
|
|
111
|
-
- `/
|
|
108
|
+
- `/design` - Thoughtful design with brainstorming expertise
|
|
109
|
+
- `/fix` - Systematic debugging with root-cause analysis
|
|
110
|
+
- `/implement` - High-quality implementation with TDD and subagents
|
|
111
|
+
- `/finish` - Verified completion with structured integration options
|
|
112
112
|
|
|
113
113
|
**See:** `.opencode/command/` for all commands
|
|
114
114
|
|
|
115
115
|
---
|
|
116
116
|
|
|
117
|
-
## Skills System (
|
|
117
|
+
## Skills System (27 skills)
|
|
118
118
|
|
|
119
|
-
**Core:** brainstorming, writing-plans, executing-plans, verification-before-completion
|
|
120
|
-
**Code:** requesting-code-review, receiving-code-review, root-cause-tracing
|
|
121
|
-
**
|
|
119
|
+
**Core:** brainstorming, writing-plans, executing-plans, verification-before-completion, using-superpowers, finishing-a-development-branch
|
|
120
|
+
**Code:** requesting-code-review, receiving-code-review, root-cause-tracing, test-driven-development, testing-anti-patterns, condition-based-waiting, defense-in-depth, systematic-debugging
|
|
121
|
+
**UI/UX:** frontend-aesthetics, mockup-to-code, visual-analysis, ui-ux-research, accessibility-audit, design-system-audit
|
|
122
|
+
**Workflow:** gemini-large-context, subagent-driven-development, dispatching-parallel-agents, using-git-worktrees, sharing-skills, writing-skills, testing-skills-with-subagents
|
|
122
123
|
|
|
123
|
-
**Note:** Skills load via `
|
|
124
|
+
**Note:** Skills load via native `skill()` tool. Commands auto-load relevant expertise.
|
|
124
125
|
|
|
125
126
|
---
|
|
126
127
|
|
|
@@ -287,9 +288,10 @@ fi
|
|
|
287
288
|
|
|
288
289
|
**"Skills not loading":**
|
|
289
290
|
|
|
290
|
-
- Skills load via
|
|
291
|
+
- Skills load via native `skill()` tool (auto-discovered)
|
|
291
292
|
- Use /design to load brainstorming
|
|
292
|
-
- Use /fix to load debugging
|
|
293
|
+
- Use /fix to load systematic-debugging
|
|
294
|
+
- Check `.opencode/skill/` directory exists
|
|
293
295
|
|
|
294
296
|
---
|
|
295
297
|
|
|
@@ -324,12 +326,12 @@ fi
|
|
|
324
326
|
- **OpenCode Docs:** https://opencode.ai/docs
|
|
325
327
|
- **Context7 API:** https://context7.com
|
|
326
328
|
- **Exa API:** https://exa.ai
|
|
327
|
-
- **Skills Documentation:**
|
|
329
|
+
- **Skills Documentation:** `.opencode/skill/`
|
|
328
330
|
- **Architecture Guide:** `AGENTS.md`
|
|
329
331
|
|
|
330
332
|
---
|
|
331
333
|
|
|
332
|
-
**OpenCodeKit v0.
|
|
334
|
+
**OpenCodeKit v0.7.0**
|
|
333
335
|
**Architecture:** Two-Layer (Memory + Beads + Git)
|
|
334
|
-
**New in v0.
|
|
335
|
-
**Last Updated:** December
|
|
336
|
+
**New in v0.7.0:** Native skill tool integration, Beads Village MCP, 27 skills, enhanced commands
|
|
337
|
+
**Last Updated:** December 30, 2025
|
|
@@ -40,6 +40,7 @@ Creating:
|
|
|
40
40
|
Type: [type]
|
|
41
41
|
Priority: [0-4]
|
|
42
42
|
Complexity: [quick/deep]
|
|
43
|
+
Role: [fe/be/mobile/devops/qa] (optional, for multi-agent)
|
|
43
44
|
|
|
44
45
|
Approve? (yes/modify)
|
|
45
46
|
```
|
|
@@ -50,6 +51,14 @@ On approval:
|
|
|
50
51
|
bd create "[title]" -t [type] -p [priority] -d "[description]" --json
|
|
51
52
|
```
|
|
52
53
|
|
|
54
|
+
**If using Beads Village for multi-agent coordination:** Add role tags so tasks can be auto-assigned to the right agent:
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
add(title="[title]", tags=["[role]"], priority=[0-4])
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
This makes the task claimable by agents with matching roles.
|
|
61
|
+
|
|
53
62
|
## Phase 4: Create Spec
|
|
54
63
|
|
|
55
64
|
```bash
|
|
@@ -6,6 +6,11 @@ agent: build
|
|
|
6
6
|
|
|
7
7
|
# Finish
|
|
8
8
|
|
|
9
|
+
**Load skills:**
|
|
10
|
+
|
|
11
|
+
- `skill({ name: "verification-before-completion" })`
|
|
12
|
+
- `skill({ name: "finishing-a-development-branch" })`
|
|
13
|
+
|
|
9
14
|
## Phase 1: Load Bead
|
|
10
15
|
|
|
11
16
|
```bash
|
|
@@ -170,6 +175,16 @@ Closes: <bead-id>"
|
|
|
170
175
|
|
|
171
176
|
## Phase 7: Close Bead
|
|
172
177
|
|
|
178
|
+
**If using Beads Village:** Complete the task and notify other agents:
|
|
179
|
+
|
|
180
|
+
```
|
|
181
|
+
done(id="$ARGUMENTS", msg="Implemented: [1-liner summary]")
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
This closes the bead, releases any file reservations, and broadcasts completion to the workspace.
|
|
185
|
+
|
|
186
|
+
**Otherwise:** Close via CLI:
|
|
187
|
+
|
|
173
188
|
```bash
|
|
174
189
|
bd close $ARGUMENTS --reason "Implemented: [1-liner summary]"
|
|
175
190
|
```
|
|
@@ -223,6 +238,8 @@ Task complete. For best performance:
|
|
|
223
238
|
Next: Create PR or merge to main
|
|
224
239
|
```
|
|
225
240
|
|
|
241
|
+
**If using Beads Village:** After calling `done()`, restart your session for a fresh context. The one-task-per-session pattern keeps agents fast and focused.
|
|
242
|
+
|
|
226
243
|
**If work was interrupted or partially complete:**
|
|
227
244
|
|
|
228
245
|
```
|
|
@@ -3,6 +3,10 @@ description: Analyze Github Actions logs and fix issues with bead tracking
|
|
|
3
3
|
argument-hint: "[github-actions-url]"
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
+
**Load skill:** `skill({ name: "systematic-debugging" })`
|
|
7
|
+
|
|
8
|
+
For deep tracing: `skill({ name: "root-cause-tracing" })`
|
|
9
|
+
|
|
6
10
|
## Github Actions URL
|
|
7
11
|
|
|
8
12
|
<url>$ARGUMENTS</url>
|
|
@@ -6,6 +6,10 @@ agent: build
|
|
|
6
6
|
|
|
7
7
|
# Implement
|
|
8
8
|
|
|
9
|
+
**Load skill:** `skill({ name: "test-driven-development" })`
|
|
10
|
+
|
|
11
|
+
For large tasks with 3+ phases, also load: `skill({ name: "subagent-driven-development" })`
|
|
12
|
+
|
|
9
13
|
## Phase 1: Setup Workspace
|
|
10
14
|
|
|
11
15
|
```bash
|
|
@@ -27,6 +31,16 @@ Create branch if not on bead branch:
|
|
|
27
31
|
git checkout -b <bead-id>
|
|
28
32
|
```
|
|
29
33
|
|
|
34
|
+
**Multi-agent coordination (if Beads Village available):**
|
|
35
|
+
|
|
36
|
+
Initialize your agent session and claim the task:
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
init(team="project", role="<your-role>")
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
This registers you in the workspace. If another agent is working on the same task, you'll be notified.
|
|
43
|
+
|
|
30
44
|
## Phase 2: Load Context
|
|
31
45
|
|
|
32
46
|
**Check for previous session work:**
|
|
@@ -96,6 +110,16 @@ Mode: [Quick/Planned]
|
|
|
96
110
|
|
|
97
111
|
## Phase 4: Implementation
|
|
98
112
|
|
|
113
|
+
**Reserve files before editing (if Beads Village available):**
|
|
114
|
+
|
|
115
|
+
Before making changes, lock the files you'll modify to prevent conflicts with other agents:
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
reserve(paths=["src/auth.ts", "src/utils/**"])
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
This creates an advisory lock. Other agents will see your reservation and avoid those files.
|
|
122
|
+
|
|
99
123
|
### With Plan (Planned Mode)
|
|
100
124
|
|
|
101
125
|
For each unchecked step in plan.md:
|
|
@@ -139,7 +163,13 @@ If "pause" or "stop": Run `/handoff <bead-id>`.
|
|
|
139
163
|
|
|
140
164
|
## Phase 6: Complete
|
|
141
165
|
|
|
142
|
-
When done:
|
|
166
|
+
When done, release any file reservations (if Beads Village available):
|
|
167
|
+
|
|
168
|
+
```
|
|
169
|
+
release()
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Then report:
|
|
143
173
|
|
|
144
174
|
```
|
|
145
175
|
Implementation Complete: <bead-id>
|
|
@@ -6,7 +6,11 @@ agent: build
|
|
|
6
6
|
|
|
7
7
|
# Integration Test: $ARGUMENTS
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
**Load skills:**
|
|
10
|
+
|
|
11
|
+
- `skill({ name: "test-driven-development" })`
|
|
12
|
+
- `skill({ name: "condition-based-waiting" })` (for async tests)
|
|
13
|
+
- `skill({ name: "testing-anti-patterns" })` (avoid common mistakes)
|
|
10
14
|
|
|
11
15
|
## Task Validation
|
|
12
16
|
|
|
@@ -16,7 +20,7 @@ Use `use_skill("test-driven-development")` for integration testing.
|
|
|
16
20
|
|
|
17
21
|
## Workflow
|
|
18
22
|
|
|
19
|
-
1. **Load skill** - `
|
|
23
|
+
1. **Load skill** - `skill({ name: "test-driven-development" })`
|
|
20
24
|
2. **Follow TDD cycle:**
|
|
21
25
|
- Write failing integration test first
|
|
22
26
|
- Verify it fails for the right reason
|
|
@@ -16,6 +16,6 @@ Fix directly with clear comments. Commit.
|
|
|
16
16
|
2. Load constraints from `.beads/artifacts/$ARGUMENTS/spec.md`
|
|
17
17
|
3. Research within scope: `/research $ARGUMENTS`
|
|
18
18
|
4. Plan approach: `/plan $ARGUMENTS`
|
|
19
|
-
5. Implement with TDD: `
|
|
19
|
+
5. Implement with TDD: `skill({ name: "test-driven-development" })`
|
|
20
20
|
6. Complete review: `.beads/artifacts/$ARGUMENTS/review.md`
|
|
21
21
|
7. Run `/finish $ARGUMENTS`
|
|
@@ -6,11 +6,11 @@ agent: build
|
|
|
6
6
|
|
|
7
7
|
# Create Skill: $ARGUMENTS
|
|
8
8
|
|
|
9
|
-
Use `
|
|
9
|
+
Use `skill({ name: "writing-skills" })` to create a new skill.
|
|
10
10
|
|
|
11
11
|
## Workflow
|
|
12
12
|
|
|
13
|
-
1. **Load skill** - `
|
|
13
|
+
1. **Load skill** - `skill({ name: "writing-skills" })`
|
|
14
14
|
2. **Follow by TDD process** - Test with subagents before writing
|
|
15
15
|
3. **Save to** `.opencode/skill/$ARGUMENTS/`
|
|
16
16
|
|
|
@@ -25,5 +25,5 @@ Use `use_skill("writing-skills")` to create a new skill.
|
|
|
25
25
|
|
|
26
26
|
## After Creation
|
|
27
27
|
|
|
28
|
-
- Test with `
|
|
29
|
-
- Share upstream with `
|
|
28
|
+
- Test with `skill({ name: "testing-skills-with-subagents" })`
|
|
29
|
+
- Share upstream with `skill({ name: "sharing-skills" })`
|
|
@@ -6,14 +6,14 @@ agent: build
|
|
|
6
6
|
|
|
7
7
|
# Optimize Skill: $ARGUMENTS
|
|
8
8
|
|
|
9
|
-
Use `
|
|
9
|
+
Use `skill({ name: "writing-skills" })` to optimize an existing skill.
|
|
10
10
|
|
|
11
11
|
## Workflow
|
|
12
12
|
|
|
13
13
|
1. **Read current skill** from `.opencode/skill/$ARGUMENTS/` or `.opencode/superpowers/skills/$ARGUMENTS/`
|
|
14
|
-
2. **Load skill** - `
|
|
14
|
+
2. **Load skill** - `skill({ name: "writing-skills" })`
|
|
15
15
|
3. **Apply TDD process** - Test, refine, verify
|
|
16
|
-
4. **Test changes** with `
|
|
16
|
+
4. **Test changes** with `skill({ name: "testing-skills-with-subagents" })`
|
|
17
17
|
|
|
18
18
|
## Optimization Goals
|
|
19
19
|
|
|
@@ -25,4 +25,4 @@ Use `use_skill("writing-skills")` to optimize an existing skill.
|
|
|
25
25
|
## After Optimization
|
|
26
26
|
|
|
27
27
|
- Verify with subagent testing
|
|
28
|
-
- Share improvements upstream with `
|
|
28
|
+
- Share improvements upstream with `skill({ name: "sharing-skills" })`
|
|
@@ -7,8 +7,8 @@ model: proxypal/gemini-3-pro-preview
|
|
|
7
7
|
|
|
8
8
|
# UI Review: $ARGUMENTS
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
skill({ name: "frontend-aesthetics" })
|
|
11
|
+
skill({ name: "visual-analysis" })
|
|
12
12
|
|
|
13
13
|
Review UI/UX design for quality, aesthetics, and best practices.
|
|
14
14
|
|