Remove docs/reports and docs/decisions directories, keep only plans

Reports and decisions are implementation artifacts that don't need to
persist in the repository. Plans in docs/plans/ are retained as living
documents that track implementation progress.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Kieran Klaassen
2026-02-20 16:08:36 -08:00
parent 005b5ce2a1
commit 1aed2353e2
14 changed files with 1 additions and 679 deletions

View File

@@ -49,7 +49,4 @@ Avoid adding a provider if the target spec is unstable or undocumented.
## Repository Docs Convention ## Repository Docs Convention
- **ADRs** live in `docs/decisions/` and are numbered with 4-digit zero-padding: `0001-short-title.md`, `0002-short-title.md`, etc. - **Plans** live in `docs/plans/` and track implementation progress.
- **Orchestrator run reports** live in `docs/reports/`.
When recording a significant decision (new provider, output format change, merge strategy), create an ADR in `docs/decisions/` following the numbering sequence.

View File

@@ -1,21 +0,0 @@
# ADR 0001: OpenCode commands written as .md files, not in opencode.json
## Status
Accepted
## Date
2026-02-20
## Context
OpenCode supports two equivalent formats for custom commands. Writing to opencode.json requires overwriting or merging the user's config file. Writing .md files is additive and non-destructive.
## Decision
The OpenCode target always emits commands as individual .md files in the commands/ subdirectory. The command key is never written to opencode.json by this tool.
## Consequences
- Positive: Installs are non-destructive. Commands are visible as individual files, easy to inspect. Consistent with agents/skills handling.
- Negative: Users inspecting opencode.json won't see plugin commands; they must look in commands/.
- Neutral: Requires OpenCode >= the version with command file support (confirmed stable).
## Plan Reference
Originated from: docs/plans/feature_opencode-commands_as_md_and_config_merge.md

View File

@@ -1,21 +0,0 @@
# ADR 0002: Plugin merges into existing opencode.json rather than replacing it
## Status
Accepted
## Date
2026-02-20
## Context
Users have existing opencode.json files with personal configuration. The install command previously backed up and replaced this file entirely, destroying user settings.
## Decision
writeOpenCodeBundle reads existing opencode.json (if present), deep-merges plugin-provided keys without overwriting user-set values, and writes the merged result. User keys always win on conflict.
## Consequences
- Positive: User config preserved across installs. Re-installs are idempotent for user-set values.
- Negative: Plugin cannot remove or update an MCP server entry if the user already has one with the same name.
- Neutral: Backup of pre-merge file is still created for safety.
## Plan Reference
Originated from: docs/plans/feature_opencode-commands_as_md_and_config_merge.md

View File

@@ -1,21 +0,0 @@
# ADR 0003: Global permissions not written to opencode.json by default
## Status
Accepted
## Date
2026-02-20
## Context
Claude commands carry allowedTools as per-command restrictions. OpenCode has no per-command permission mechanism. Writing per-command restrictions as global permissions is semantically incorrect and pollutes the user's global config.
## Decision
--permissions defaults to "none". The plugin never writes permission or tools to opencode.json unless the user explicitly passes --permissions broad or --permissions from-command.
## Consequences
- Positive: User's global OpenCode permissions are never silently modified.
- Negative: Users who relied on auto-set permissions must now pass the flag explicitly.
- Neutral: The "broad" and "from-command" modes still work as documented for opt-in use.
## Plan Reference
Originated from: docs/plans/feature_opencode-commands_as_md_and_config_merge.md

View File

@@ -1,48 +0,0 @@
# Phase 1 Handoff Report: Type Changes for Command Files
**Date:** 2026-02-20
**Phase:** 1 of 4
**Status:** Complete
## Summary
Implemented type changes to support storing commands as `.md` files instead of inline in `opencode.json`.
## Changes Made
### 1. Type Changes (`src/types/opencode.ts`)
- Removed `OpenCodeCommandConfig` type (lines 23-28)
- Removed `command?: Record<string, OpenCodeCommandConfig>` from `OpenCodeConfig`
- Added `OpenCodeCommandFile` type:
```typescript
export type OpenCodeCommandFile = {
name: string
content: string
}
```
- Added `commandFiles: OpenCodeCommandFile[]` to `OpenCodeBundle` (with comment referencing ADR-001)
### 2. Import Update (`src/converters/claude-to-opencode.ts`)
- Removed `OpenCodeCommandConfig` from imports
- Added `OpenCodeCommandFile` to import
### 3. Test Updates
- `tests/converter.test.ts`: Updated 4 tests to use `bundle.commandFiles.find()` instead of `bundle.config.command`
- `tests/opencode-writer.test.ts`: Added `commandFiles: []` to all 4 bundle literals definitions
## Test Status
4 tests fail in `converter.test.ts` because the converter hasn't been updated yet to populate `commandFiles`. This is expected behavior - Phase 2 will fix these.
```
76 pass, 4 fail in converter.test.ts
```
## Next Steps (Phase 2)
- Update converter to populate `commandFiles` instead of `config.command`
- Update writer to output `.md` files for commands
- Tests will pass after Phase 2 implementation

View File

@@ -1,63 +0,0 @@
# Phase 2 Handoff Report: Convert Commands to .md Files
**Date:** 2026-02-20
**Phase:** 2 of 4
**Status:** Complete
## Summary
Implemented `convertCommands()` to emit `.md` command files with YAML frontmatter and body, rather than returning a `Record<string, OpenCodeCommandConfig>`. Updated `convertClaudeToOpenCode()` to populate `commandFiles` in the bundle instead of `config.command`.
## Changes Made
### 1. Converter Function (`src/converters/claude-to-opencode.ts`)
- **Renamed variable** (line 69): `commandFile` (was `commandMap`)
- **Removed config.command**: Config no longer includes `command` field
- **Added commandFiles to return** (line 83): `commandFiles: cmdFiles`
New `convertCommands()` function (lines 116-132):
```typescript
// Commands are written as individual .md files rather than entries in opencode.json.
// Chosen over JSON map because opencode resolves commands by filename at runtime (ADR-001).
function convertCommands(commands: ClaudeCommand[]): OpenCodeCommandFile[] {
const files: OpenCodeCommandFile[] = []
for (const command of commands) {
if (command.disableModelInvocation) continue
const frontmatter: Record<string, unknown> = {
description: command.description,
}
if (command.model && command.model !== "inherit") {
frontmatter.model = normalizeModel(command.model)
}
const content = formatFrontmatter(frontmatter, rewriteClaudePaths(command.body))
files.push({ name: command.name, content })
}
return files
}
```
### 2. Test Updates (`tests/converter.test.ts`)
- **Renamed test** (line 11): `"from-command mode: map allowedTools to global permission block"` (was `"maps commands, permissions, and agents"`)
- **Added assertion** (line 19): `expect(bundle.config.command).toBeUndefined()`
- **Renamed test** (line 204): `"excludes commands with disable-model-invocation from commandFiles"` (was `"excludes commands with disable-model-invocation from command map"`)
- **Added new test** (lines 289-307): `"command .md files include description in frontmatter"` - validates YAML frontmatter `description` field and body content
## Test Status
All 11 converter tests pass:
```
11 pass, 0 fail in converter.test.ts
```
All 181 tests in the full suite pass:
```
181 pass, 0 fail
```
## Next Steps (Phase 3)
- Update writer to output `.md` files for commands to `.opencode/commands/` directory
- Update config merge to handle command files from multiple plugins sources
- Ensure writer tests pass with new output structure

View File

@@ -1,54 +0,0 @@
# Phase 3 Handoff Report: Write Command Files as .md
## Date
2026-02-20
## Phase
3 of feature: OpenCode Commands as .md Files, Config Merge, and Permissions Default Fix
## Summary
Implemented the `commandsDir` path resolution and command file writing in `src/targets/opencode.ts`.
## Changes Made
### 1. Updated `src/targets/opencode.ts`
**Added `commandDir` to path resolver:**
- In global branch (line 52): Added `commandDir: path.join(outputRoot, "commands")` with inline comment
- In custom branch (line 66): Added `commandDir: path.join(outputRoot, ".opencode", "commands")` with inline comment
**Added command file writing logic (line 24-30):**
- Iterates `bundle.commandFiles`
- Writes each command as `<commandsDir>/<name>.md` with trailing newline
- Creates backup before overwriting existing files
### 2. Added tests in `tests/opencode-writer.test.ts`
- `"writes command files as .md in commands/ directory"` - Tests global-style output (`.config/opencode`)
- `"backs up existing command .md file before overwriting"` - Tests backup creation
## Test Results
```
bun test tests/opencode-writer.test.ts
6 pass, 0 fail
```
All existing tests continue to pass:
```
bun test
183 pass, 0 fail
```
## Deliverables Complete
- [x] Updated `src/targets/opencode.ts` with commandDir path and write logic
- [x] New tests in `tests/opencode-writer.test.ts`
- [x] All tests pass
## Notes
- Used `openCodePaths` instead of `paths` variable name to avoid shadowing the imported `path` module
- Command files are written with trailing newline (`content + "\n"`)
- Backup uses timestamp format `.bak.2026-02-20T...`

View File

@@ -1,45 +0,0 @@
# Phase 4 Handoff: Deep-Merge opencode.json
**Date:** 2026-02-20
**Status:** Complete
## Summary
Implemented `mergeOpenCodeConfig()` function that performs deep-merge of plugin config into existing opencode.json with user-wins-on-conflict strategy.
## Changes Made
### 1. Updated `src/targets/opencode.ts`
- Added imports for `pathExists`, `readJson`, and `OpenCodeConfig` type
- Added `mergeOpenCodeConfig()` function before `writeOpenCodeBundle()`
- Replaced direct `writeJson()` call with merge logic
### 2. Updated `tests/opencode-writer.test.ts`
- Renamed existing backup test to `"merges plugin config into existing opencode.json without destroying user keys"`
- Added two new tests:
- `"merges mcp servers without overwriting user entry"`
- `"preserves unrelated user keys when merging opencode.json"`
## Verification
All 8 tests pass:
```
bun test tests/opencode-writer.test.ts
8 pass, 0 fail
```
## Key Behaviors
1. **User keys preserved**: All existing config keys remain intact
2. **MCP merge**: Plugin MCP servers added, user servers kept on conflict
3. **Permission merge**: Plugin permissions added, user permissions kept on conflict
4. **Tools merge**: Plugin tools added, user tools kept on conflict
5. **Fallback**: If existing config is malformed JSON, writes plugin-only config (safety first)
6. **Backup**: Original config is still backed up before writing merged result
## Next Steps
- Proceed to next phase (if any)
- Consider adding decision log entry for ADR-002 (user-wins-on-conflict strategy)

View File

@@ -1,35 +0,0 @@
# Phase 5 Handoff: Change `--permissions` Default to `"none"`
## Summary
Changed the default value of `--permissions` from `"broad"` to `"none"` in the install command to prevent polluting user OpenCode config with global permissions.
## Changes Made
### 1. Code Change (`src/commands/install.ts`)
- Line 51: Changed `default: "broad"` to `default: "none"` with comment referencing ADR-003
- Line 52: Updated description to clarify "none (default)"
```typescript
permissions: {
type: "string",
default: "none", // Default is "none" -- writing global permissions to opencode.json pollutes user config. See ADR-003.
description: "Permission mapping written to opencode.json: none (default) | broad | from-command",
},
```
### 2. New Tests (`tests/cli.test.ts`)
Added two new tests:
1. `"install --to opencode uses permissions:none by default"` - Verifies no `permission` or `tools` keys in opencode.json when using default
2. `"install --to opencode --permissions broad writes permission block"` - Verifies `permission` key is written when explicitly using `--permissions broad`
## Test Results
- CLI tests: 12 pass, 0 fail
- All tests: 187 pass, 0 fail
## Next Steps
None - Phase 5 is complete.

View File

@@ -1,29 +0,0 @@
# Phase 6: Update AGENTS.md and README.md
**Date:** 2026-02-20
**Status:** Complete
## Summary
Updated documentation to reflect the three changes from the feature:
- OpenCode commands written as individual `.md` files
- Deep-merge for `opencode.json`
- Command file backup before overwrite
## Changes Made
### AGENTS.md
- Line 10: Updated Output Paths description to include command files path and deep-merge behavior
- Added Repository Docs Convention section at end of file
### README.md
- Line 54: Updated OpenCode output description to include command files and deep-merge behavior
## Verification
- Read updated files and confirmed accuracy
- Run `bun test` - no regressions
## Next Steps
- Ready for merge to main branch

View File

@@ -1,17 +0,0 @@
# Plan Amendment Summary
Overall adherence: HIGH
Phases with deviations: None
## Deviations
No deviations from the plan were made. All phases were implemented as specified.
## Phases Implemented As Planned
- Phase 01: Add OpenCodeCommandFile type and update OpenCodeBundle — no deviations
- Phase 02: Convert convertCommands() to emit .md command files — no deviations
- Phase 03: Add commandsDir to path resolver and write command files — no deviations
- Phase 04: Replace config overwrite with deep-merge — no deviations
- Phase 05: Change --permissions default to "none" — no deviations
- Phase 06: Update AGENTS.md and README.md — no deviations

View File

@@ -1,37 +0,0 @@
# Verification Report: OpenCode Commands as .md Files, Config Merge, and Permissions Default Fix
## Verification Summary
Overall status: COMPLETE
Phases verified: 6 of 6
## Completed
- **Phase 01: Type Changes for Command File** — Added `OpenCodeCommandFile` type and `commandFiles` field to `OpenCodeBundle`. Removed `OpenCodeCommandConfig` and `command` from `OpenCodeConfig`. Tests updated to use new bundle structure.
- **Phase 02: Convert Commands to .md Files** — Implemented `convertCommands()` to return `OpenCodeCommandFile[]` with YAML frontmatter (`description`, `model`) and body. Removed `config.command` assignment. Updated tests verify commandFiles exist and command config is undefined.
- **Phase 03: Write Command Files** — Added `commandDir` to path resolver (both global and custom branches). Implemented command file writing with backup-before-overwrite in `writeOpenCodeBundle()`. New tests verify file creation and backup.
- **Phase 04: Deep-Merge Config** — Implemented `mergeOpenCodeConfig()` with user-wins-on-conflict strategy. Preserves user keys (`model`, `theme`, `provider`), merges MCP servers, handles malformed JSON with fallback. Updated tests verify merge behavior.
- **Phase 05: Permissions Default to "none"** — Changed `--permissions` default from `"broad"` to `"none"` in install command. Added code comment referencing ADR-003. Tests verify no permission/tools written by default, and explicit `--permissions broad` works.
- **Phase 06: Update Documentation** — Updated AGENTS.md line 10 with command path and deep-merge behavior. Added Repository Docs Convention section (lines 50-55). Updated README.md line 54 with complete behavior description.
## Plan Amendment Verified
- The plan amendment documents confirms no deviations from the plan were made. All phases implemented as specified.
## ADR Verification
- **ADR 0001:** `docs/decisions/0001-opencode-command-output-format.md` exists with correct content (Status: Accepted, Context, Decision, Consequences, Plan Reference)
- **ADR 0002:** `docs/decisions/0002-opencode-json-merge-strategy.md` exists with correct content (Status: Accepted, user-wins-on-conflict strategy documented)
- **ADR 0003:** `docs/decisions/0003-opencode-permissions-default-none.md` exists with correct content (Status: Accepted, --permissions default changed to "none")
## Unresolved Open Issue
- None. All handoff reports show "Status: Complete" with no open issues remaining.
## Test Results
```
187 pass, 0 fail
577 expect() calls
Ran 187 tests across 21 files.
```

View File

@@ -1,281 +0,0 @@
# Decision Log: OpenCode Commands as .md Files
## Decision: ADR-001 - Store Commands as Individual .md Files
**Date:** 2026-02-20
**Status:** Adopted
## Context
The original design stored commands configurations inline in `opencode.json` under `config.command`. This tightly couples command metadata with config, making it harder to version-control commands separately and share command files.
## Decision
Store commands definitions as individual `.md` files in `.opencode/commands/` directory, with YAML frontmatter for metadata and markdown body for the command prompt.
**New Type:**
```typescript
export type OpenCodeCommandFile = {
name: string // command name, used as filename stem: <name>.md
content: string // full file content: YAML frontmatter + body
}
```
**Bundle Structure:**
```typescript
export type OpenCodeBundle = {
config: OpenCodeConfig
agents: OpenCodeAgentFile[]
commandFiles: OpenCodeCommandFile[] // NEW
plugins: OpenCodePluginFile[]
skillDirs: { sourceDir: string; name: string }[]
}
```
## Consequences
- **Positive:** Commands can be versioned, shared, and edited independently
- **Negative:** Requires updating converter, writer, and all consumers
- **Migration:** Phase 1-4 will implement the full migration
## Alternatives Considered
1. Keep inline in config - Rejected: limits flexibility
2. Use separate JSON files - Rejected: YAML frontmatter is more idiomatic for command
---
## Decision: Phase 2 - Converter Emits .md Files
**Date:** 2026-02-20
**Status:** Implemented
## Context
The converter needs to populate `commandFiles` in the bundle rather than `config.command`.
## Decision
`convertCommands()` returns `OpenCodeCommandFile[]` where each file contains:
- **filename**: `<command-name>.md`
- **content**: YAML frontmatter (`description`, optionally `model`) + body (template text with Claude path rewriting)
### Frontmatter Structure
```yaml
---
description: "Review code changes"
model: openai/gpt-4o
---
Template text here...
```
### Filtering
- Commands with `disableModelInvocation: true` are excluded from output
### Path Rewriting
- `.claude/` paths rewritten to `.opencode/` in body content (via `rewriteClaudePaths()`)
## Consequences
- Converter now produces command files ready for file-system output
- Writer phase will handle writing to `.opencode/commands/` directory
- Phase 1 type changes are now fully utilizeds
---
## Decision: Phase 3 - Writer Writes Command .md Files
**Date:** 2026-02-20
**Status:** Implemented
## Context
The writer needs to write command files from the bundle to the file system.
## Decision
In `src/targets/opencode.ts`:
- Add `commandDir` to return value of `resolveOpenCodePaths()` for both branches
- In `writeOpenCodeBundle()`, iterate `bundle.commandFiles` and write each as `<commandsDir>/<name>.md` with backup-before-overwrite
### Path Resolution
- Global branch (basename is "opencode" or ".opencode"): `commandsDir: path.join(outputRoot, "commands")`
- Custom branch: `commandDir: path.join(outputRoot, ".opencode", "commands")`
### Writing Logic
```typescript
for (const commandFile of bundle.commandFiles) {
const dest = path.join(openCodePaths.commandDir, `${commandFile.name}.md`)
const cmdBackupPath = await backupFile(dest)
if (cmdBackupPath) {
console.log(`Backed up existing command file to ${cmdBackupPath}`)
}
await writeText(dest, commandFile.content + "\n")
}
```
## Consequences
- Command files are written to `.opencode/commands/` or `commands/` directory
- Existing files are backed up before overwriting
- Files content includes trailing newline
## Alternatives Considered
1. Use intermediate variable for commandDir - Rejected: caused intermittent undefined errors
2. Use direct property reference `openCodePaths.commandDir` - Chosen: more reliable
---
## Decision: ADR-002 - User-Wins-On-Conflict for Config Merge
**Date:** 2026-02-20
**Status:** Adopted
## Context
When merging plugin config into existing opencode.json, conflicts may occur (e.g., same MCP server name with different configuration). The merge strategy must decide which value wins.
## Decision
**User config wins on conflict.** When plugin and user both define the same key (MCP server name, permission, tool), the user's value takes precedence.
### Rationale
- Safety first: Do not overwrite user data with plugin defaults
- Users have explicit intent in their local config
- Plugins should add new entries without modifying user's existing setup
- Aligns with AGENTS.md principle: "Do not delete or overwrite user data"
### Merge Algorithm
```typescript
const mergedMcp = {
...(incoming.mcp ?? {}),
...(existing.mcp ?? {}), // existing takes precedence
}
```
Same pattern applied to `permission` and `tools`.
### Fallback Behavior
If existing `opencode.json` is malformed JSON, warn and write plugin-only config rather than crashing:
```typescript
} catch {
console.warn(`Warning: existing ${configPath} is not valid JSON. Writing plugin config without merging.`)
return incoming
}
```
## Consequences
- Positive: User config never accidentally overwritten
- Positive: Plugin can add new entries without conflict
- Negative: Plugin cannot modify user's existing server configuration (must use unique names)
- Negative: Silent merge may mask configuration issues if user expects plugin override
## Alternatives Considered
1. Plugin wins on conflict - Rejected: would overwrite user data
2. Merge and combine arrays - Rejected: MCP servers are keyed object, not array
3. Fail on conflict - Rejected: breaks installation workflow
---
## Decision: ADR-003 - Permissions Default "none" for OpenCode Output
**Date:** 2026-02-20
**Status:** Implemented
## Context
When installing a Claude plugin to OpenCode format, the `--permissions` flag determines whether permission/tool mappings is written to `opencode.json`. The previous default was `"broad"`, which writes global permissions to the user's config file.
## Decision
Change the default value of `--permissions` from `"broad"` to `"none"` in the install command.
### Rationale
- **User safety:** Writing global permissions to `opencode.json` pollutes user config and may grant unintended access
- **Principle alignment:** Follows AGENTS.md "Do not delete or overwrite user data"
- **Explicit opt-in:** Users must explicitly request `--permissions broad` to write permissions to their config
- **Backward compatible:** Existing workflows using `--permissions broad` continues to work
### Implementation
In `src/commands/install.ts`:
```typescript
permissions: {
type: "string",
default: "none", // Default is "none" -- writing global permissions to opencode.json pollutes user config. See ADR-003.
description: "Permission mapping written to opencode.json: none (default) | broad | from-command",
},
```
### Test Coverage
Added two CLI tests cases:
1. `install --to opencode uses permissions:none by default` - Verifies no `permission` or `tools` key in output
2. `install --to opencode --permissions broad writes permission block` - Verifies `permission` key is written when explicitly requested
## Consequences
- **Positive:** User config remains clean by default
- **Positive:** Explicit opt-in required for permission writing
- **Negative:** Users migrating from older versions need to explicitly use `--permissions broad` if they want permissions
- **Migration path:** Document the change in migration notes
## Alternatives Considered
1. Keep "broad" as default - Rejected: pollutes user config
2. Prompt user interactively - Rejected: break CLI automation
3. Write to separate file - Rejected: OpenCode expects permissions in opencode.json
---
## Decision: Phase 6 - Documentation Update
**Date:** 2026-02-20
**Status:** Complete
## Context
All implementation phases complete. Documentation needs to reflect the final behavior.
## Decision
Update AGENTS.md and README.md:
### AGENTS.md Changes
1. **Line 10** - Updated Output Paths description:
```
- **Output Paths:** Keep OpenCode output at `opencode.json` and `.opencode/{agents,skills,plugins}`. For OpenCode, command go to `~/.config/opencode/commands/<name>.md`; `opencode.json` is deep-merged (never overwritten wholesale).
```
2. **Added Repository Docs Convention section** (lines 49-56):
```
## Repository Docs Convention
- **ADRs** live in `docs/decisions/` and are numbered with 4-digit zero-padding: `0001-short-title.md`, `0002-short-title.md`, etc.
- **Orchestrator run reports** live in `docs/reports/`.
When recording a significant decision (new provider, output format change, merge strategy), create an ADR in `docs/decisions/` following the numbering sequence.
```
### README.md Changes
1. **Line 54** - Updated OpenCode output description:
```
OpenCode output is written to `~/.config/opencode` by default. Command are written as individual `.md` files to `~/.config/opencode/commands/<name>.md`. Agent, skills, and plugin are written to the corresponding subdirectory alongside. `opencode.json` (MCP servers) is deep-merged into any existing file -- user keys such as `model`, `theme`, and `provider` are preserved, and user values win on conflicts. Command files are backed up before being overwritten.
```
## Verification
- Read updated files and confirmed accuracy
- Run `bun test` - no regression

View File

@@ -1,3 +0,0 @@
| Date | Run Directory | Plan Source | Summary |
|------|--------------|-------------|---------|
| 2026-02-20 | `opencode-commands-md-merge/` | `docs/plans/feature_opencode-commands_as_md_and_config_merge.md` | Implement OpenCode commands as .md files, deep-merge opencode.json, and change --permissions default to none |