Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 149 additions & 0 deletions docs/adr/0008-canonical-opencode-project-configuration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
# ADR-0008: Canonical OpenCode project configuration

- Status: Accepted
- Date: 2026-06-17
- Approved by: Repository owner
- Approved at: 2026-06-17T19:17:43Z
- Related finding: REPO-AUDIT-F-004
Comment thread
MerverliPy marked this conversation as resolved.
- Related redesign blocker: B-4

## Context

The repository currently contains both `opencode.json` and `opencode.jsonc`.
They define materially different defaults and permissions:

- `opencode.json` selects `mobile-ui-orchestrator`, supplies project instruction
files, permits several read-only tools, permits skills, and requires approval
for delegated tasks.
- `opencode.jsonc` selects `plan`, applies path-sensitive secret protections,
denies skills and delegated tasks, and blocks destructive or publishing
commands.

OpenCode 1.17.7 merges both project files. The currently resolved configuration
therefore contains values from both files, with `opencode.jsonc` overriding
conflicting values.

This makes repository policy dependent on undocumented merge behavior. A
maintainer can edit one file believing it is authoritative while the other file
changes the effective result.

The repository documentation already instructs operators to start in the
default `plan` agent. The external repository audit also recommends retaining
the stricter permission baseline.

## Decision

The repository will use exactly one canonical project configuration:

- Canonical file: `opencode.jsonc`
- Default agent: `plan`
- OpenCode version: exactly `1.17.7`
- `opencode.json` will be removed

The canonical configuration must preserve the security-sensitive policy from
the existing `opencode.jsonc`:

- secret, credential, private-key, environment-file, and Git metadata read
restrictions;
- equivalent edit restrictions;
- delegated task and skill denial;
- approval for unclassified shell commands;
- explicit denial of destructive Git, infrastructure, publication, privilege,
and destructive filesystem commands;
- disabled sharing;
- denied external-directory access.

The canonical configuration must also preserve non-conflicting values that are
part of the currently resolved project configuration:

- project instruction files:
- `AGENTS.md`
- `.ui-redesign/adapter/REPOSITORY_ADAPTER.md`
- `.ui-redesign/decisions/DECISION_LEDGER.md`
- explicit read-only tool allowances for:
- `glob`
- `grep`
- `list`
- `lsp`
- `todowrite`
- `question`

The canonical file will retain the existing `opencode.jsonc` watcher,
tool-output, compaction, snapshot, update-notification, and permission settings
unless a separately reviewed change documents a reason to alter them.

The root package will pin `opencode-ai` to exact version `1.17.7`. Repository
validation will invoke the local package binary rather than relying on an
unversioned user-level installation.

An effective-configuration smoke test will verify at minimum:

1. exactly one root OpenCode configuration exists;
2. the local OpenCode version is `1.17.7`;
3. the resolved default agent is `plan`;
4. sharing remains disabled;
5. all required instruction files are loaded;
6. task and skill permissions remain denied;
7. external-directory access remains denied;
8. protected read and edit patterns remain denied;
9. destructive and publishing commands remain denied;
10. expected read-only tools remain allowed.

The smoke test must isolate or explicitly disclose user-level and environment
configuration sources so a developer-specific override cannot make the
repository test pass accidentally.

## Consequences

### Positive

- Project policy has one authoritative source.
- The effective default agent and permissions are reviewable without relying on
configuration merge order.
- OpenCode runtime behavior is tied to a reproducible version.
- Regression testing detects permission or default-agent drift.
- The mobile redesign instruction files remain active while the stricter
permission baseline is preserved.

### Negative and risks

- Installing the pinned CLI adds platform-specific optional dependencies and a
package postinstall step.
- Developers with unsupported platforms must use a separately reviewed
installation method.
- User-level, environment-provided, or future global OpenCode configuration can
still affect an interactive session.
- Setting `task` and `skill` to `deny` intentionally prevents delegation from
this default configuration. Any future delegation-enabled profile requires a
separate reviewed configuration and decision.

## Alternatives considered

### Keep both files and document merge order

Rejected. The effective policy would remain dependent on version-specific merge
behavior and would still be easy to edit incorrectly.

### Make `opencode.json` canonical

Rejected. It has weaker secret-path controls, permits skills, permits delegated
tasks subject to approval, and selects a redesign-specific orchestrator as the
general project default.

### Keep only the current `opencode.jsonc` without copying resolved values

Rejected. Removing `opencode.json` would also remove the project instruction
list and explicit read-only tool allowances that are currently contributed by
that file.

### Do not pin OpenCode

Rejected. Configuration semantics and effective permissions could change when
the developer installation changes.

## Rollback

Revert the consolidation commit and stop OpenCode use until the conflicting
configuration state is reviewed. Restoring both root configuration files while
continuing normal OpenCode operation is not an acceptable steady-state
rollback.
42 changes: 0 additions & 42 deletions opencode.json

This file was deleted.

36 changes: 21 additions & 15 deletions opencode.jsonc
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
{
"$schema": "https://opencode.ai/config.json",
// Canonical project configuration. Keep exactly one root OpenCode config.
// Change this policy only with an effective-config regression test.
"default_agent": "plan",
"share": "disabled",
"snapshot": true,
"autoupdate": "notify",
"instructions": [
"AGENTS.md",
".ui-redesign/adapter/REPOSITORY_ADAPTER.md",
".ui-redesign/decisions/DECISION_LEDGER.md",
],
"watcher": {
"ignore": [
".git/**",
"node_modules/**",
"dist/**",
".turbo/**",
"coverage/**",
".next/**"
]
"ignore": [".git/**", "node_modules/**", "dist/**", ".turbo/**", "coverage/**", ".next/**"],
},
"tool_output": {
"max_lines": 500,
"max_bytes": 40000
"max_bytes": 40000,
},
"compaction": {
"auto": true,
"prune": true,
"tail_turns": 3,
"reserved": 12000
"reserved": 12000,
},
"permission": {
"read": {
Expand All @@ -40,8 +40,14 @@
"*credentials*": "deny",
"**/*credentials*": "deny",
".git/**": "deny",
"**/.git/**": "deny"
"**/.git/**": "deny",
},
"glob": "allow",
"grep": "allow",
"list": "allow",
"lsp": "allow",
"todowrite": "allow",
"question": "allow",
"edit": {
"*": "ask",
"*.env": "deny",
Expand All @@ -55,7 +61,7 @@
"*credentials*": "deny",
"**/*credentials*": "deny",
".git/**": "deny",
"**/.git/**": "deny"
"**/.git/**": "deny",
},
"external_directory": "deny",
"webfetch": "ask",
Expand Down Expand Up @@ -92,7 +98,7 @@
"kubectl apply*": "deny",
"helm upgrade*": "deny",
"npm publish*": "deny",
"pnpm publish*": "deny"
}
}
"pnpm publish*": "deny",
},
},
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"@typescript-eslint/eslint-plugin": "^7.0.0",
"@typescript-eslint/parser": "^7.0.0",
"eslint": "^8.57.0",
"opencode-ai": "1.17.7",
"pg": "^8.13.0",
"prettier": "^3.4.0",
"tsx": "^4.22.4",
Expand Down
Loading
Loading