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
12 changes: 12 additions & 0 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

100 changes: 100 additions & 0 deletions docs/ai-guardrails/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# OpenCode Internal Guardrails Plan

This document defines the production plan for building an internal AI coding environment on top of OpenCode without turning the repo into a long-lived fork.

## Product framing

The target product should be described consistently across README, issues, and future docs as:

- a Cor-Incorporated fork of OpenCode
- intentionally upstream-compatible where practical
- extended through a thin internal distribution layer
- not an official upstream OpenCode release channel

The migration goal is not to hide the upstream lineage. It is to make the fork legible while keeping core drift low.

## Operating principles

This plan inherits the key philosophy from `claude-code-skills` epic `#130`, its README, and its ADRs:

- enforce quality and safety through mechanism before prose
- push checks to the fastest reliable layer first
- keep always-loaded instructions pointer-based and short
- treat deployment/runtime verification as a separate requirement from code review
- prefer explicit workflow gates for review, CI, and release-sensitive operations

That means the migration target is not "copy Claude hooks as-is." It is "preserve the operating model using OpenCode-native config, plugins, commands, permissions, and CI."

## Goal

Bootstrap the first thin-distribution slice that keeps OpenCode upstream-friendly while adding:

- managed configuration for enterprise control
- localhost-only server defaults
- disabled sharing by default
- a pinned wrapper entrypoint
- scenario tests that pin config precedence and project-local compatibility

## Non-goals

- a deep rewrite of OpenCode core
- default use of preview or free third-party models for confidential code
- direct AI-driven push, merge, or release without explicit workflow gates
- always-on remote config, remote instructions, or unbounded MCP expansion

## Baseline facts

- OpenCode already supports `AGENTS.md`, managed config, commands, agents, skills, and permissions.
- Managed config and custom config directories are enough to ship a first internal distribution without a deep core fork.
- Scenario tests in `packages/opencode` can validate precedence and compatibility without special product code paths.

## Product requirements

### Architecture

- Keep OpenCode as the upstream engine.
- Add a wrapper distribution, not a deep fork.
- Store organization defaults in managed config and project config, not in scattered local scripts.
- Default server exposure to localhost-only and default sharing to disabled.

### First slice

- Keep OpenCode as the upstream engine.
- Add a wrapper distribution, not a deep fork.
- Store organization defaults in managed config and packaged profile files, not in scattered scripts.
- Default server exposure to localhost-only and default sharing to disabled.
- Prove config precedence and project-local compatibility with scenario tests.

## Delivery phases

1. Freeze architecture decisions in ADRs.
2. Land the thin-distribution bootstrap as the first issue-sized slice.
3. Keep scenario coverage in the same change set as runtime behavior.
4. Stack later issues for plugin policy, safe workflows, provider lanes, and replay coverage on top of this base.

## Tracking

- Epic: [#1](https://github.com/Cor-Incorporated/opencode/issues/1)
- Current issue: [#2](https://github.com/Cor-Incorporated/opencode/issues/2)
- Future slices remain separate issues so implementation can stay one issue per pull request.

## Session rule

When continuing this work in future sessions:

- start from the GitHub epic and the linked issue, not from memory
- preserve upstream compatibility unless a missing extension point proves otherwise
- update docs and tests in the same change set when guardrail behavior changes
- do not mark work complete unless runtime behavior is verified, not just implemented

## Artifact map

- ADRs: `docs/ai-guardrails/adr/`
- Issue briefs: `docs/ai-guardrails/issues/`
- Scenario tests: `packages/opencode/test/scenario/`
- Thin distribution package: `packages/guardrails/`

## Primary references

- OpenCode config: https://opencode.ai/docs/config
- OpenCode server: https://opencode.ai/docs/server
38 changes: 38 additions & 0 deletions docs/ai-guardrails/adr/001-thin-distribution-over-deep-fork.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# ADR 001: Thin Distribution Over Deep Fork

- Status: Accepted
- Date: 2026-04-03

## Context

The internal product needs enterprise guardrails, provider policy, and Claude asset migration. OpenCode already exposes the primitives needed to do this through config layering, managed settings, plugins, commands, agents, and server APIs.

A deep fork would create a permanent rebase tax, make upstream updates harder, and encourage product logic to drift into core files that are not unique to the internal distribution.

## Decision

Build the internal product as a thin distribution:

- keep upstream OpenCode pinned and trackable
- prefer wrapper CLI, managed config, project config, `.opencode` assets, and plugins
- treat core patches as exceptions that must be justified by a missing extension point

## Consequences

### Positive

- lower upstream merge cost
- easier security and version upgrades
- clearer separation between platform behavior and organization policy
- easier scenario testing because policy lives at the edges

### Negative

- some existing Claude hooks must be redesigned instead of copied 1:1
- workflow control depends on configuration discipline and tests

## Evidence

- OpenCode config precedence and managed config support: https://opencode.ai/docs/config
- OpenCode plugins and hook surface: https://opencode.ai/docs/plugins
- OpenCode commands and agents: https://opencode.ai/docs/commands and https://opencode.ai/docs/agents
38 changes: 38 additions & 0 deletions docs/ai-guardrails/adr/004-scenario-tests-before-productization.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# ADR 004: Scenario Tests Before Productization

- Status: Accepted
- Date: 2026-04-03

## Context

The internal distribution will add policy, not just features. Policy breaks quietly when config precedence, plugin hooks, or compatibility discovery shifts under upstream changes.

Unit tests are necessary but not sufficient. The contract that matters is scenario behavior across config, discovery, and plugin wiring.

## Decision

Add scenario tests before product code for these contracts:

- managed config overrides weaker config layers for enterprise restrictions
- Claude-compatible skills remain discoverable during migration
- plugin hooks can inject environment and observe session lifecycle events

Future work should extend this suite with replay tests for release gates, provider admission, and share/server restrictions.

## Consequences

### Positive

- safer upstream upgrades
- easier AI-driven implementation because expected behavior is executable
- faster detection of regressions in config precedence and plugin surfaces

### Negative

- test fixtures must stay aligned with evolving config semantics

## Evidence

- OpenCode config precedence and managed settings: https://opencode.ai/docs/config
- OpenCode plugin events: https://opencode.ai/docs/plugins
- OpenCode skills and commands: https://opencode.ai/docs/skills and https://opencode.ai/docs/commands
29 changes: 29 additions & 0 deletions docs/ai-guardrails/issues/001-bootstrap-thin-distribution.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Issue 001: Bootstrap Thin Distribution

## Problem

The repo needs a first internal distribution layer that can enforce organization defaults without forking core behavior into unrelated files.

## Deliverables

- wrapper entrypoint for the internal distribution
- pinned OpenCode version strategy
- managed config profile for enterprise defaults
- localhost-only server default
- default `share: "disabled"`

## Acceptance

- internal launcher resolves to a pinned OpenCode build
- managed config overrides weaker config layers in tests
- project config can still add project-local commands, skills, and agents

## Dependencies

- ADR 001
- ADR 004

## Sources

- https://opencode.ai/docs/config
- https://opencode.ai/docs/server
75 changes: 75 additions & 0 deletions packages/guardrails/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Guardrails Distribution

This package is the thin internal distribution layer for the guardrails plan.

It should be understood as the Cor-Incorporated-specific layer that sits on top of upstream-compatible OpenCode, not as a separate reimplementation of the core runtime.

It keeps upstream OpenCode as the runtime and adds organization policy at the edges:

- `bin/opencode-guardrails` sets `OPENCODE_CONFIG_DIR` to the packaged profile and then delegates to the pinned `opencode` dependency
- `managed/opencode.json` is the admin-managed profile for system deployment
- `profile/` contains the packaged custom config dir defaults, starting with `AGENTS.md` and `opencode.json`

## Design intent

This package exists to preserve the operating model imported from `claude-code-skills` without turning OpenCode into a deep fork.

- mechanism-first guardrails
- fast feedback before slower workflow gates
- pointer-based instructions instead of bloated always-loaded prompts
- runtime verifiability over "the code exists, so it must work"

Those principles come from `claude-code-skills` epic `#130` and are tracked in this fork under `docs/ai-guardrails/`.

## Positioning

When describing this package or this fork externally, use wording close to:

- forked from OpenCode
- compatibility with upstream preserved where practical
- Cor-Incorporated-specific policy and workflow layer added in `packages/guardrails`

Avoid wording that implies this package replaces OpenCode itself. The intended architecture is still upstream engine plus thin internal distribution.

## Upstream strategy

- Keep this package version aligned with `packages/opencode/package.json`
- Upgrade upstream first, then update this package only where the extension surface changed
- Prefer `managed/` and `profile/` assets over core patches

## Current scope

Current contents focus on the first thin-distribution slice:

- packaged wrapper entrypoint
- managed enterprise defaults
- packaged custom config dir profile
- scenario coverage for managed config precedence and project-local asset compatibility

Planned next slices are tracked in the fork:

- epic [#1](https://github.com/Cor-Incorporated/opencode/issues/1)
- plugin MVP [#4](https://github.com/Cor-Incorporated/opencode/issues/4)
- safe agents and commands [#5](https://github.com/Cor-Incorporated/opencode/issues/5)
- provider policy [#6](https://github.com/Cor-Incorporated/opencode/issues/6)
- scenario/replay harness [#7](https://github.com/Cor-Incorporated/opencode/issues/7)

## Usage

Run the wrapper directly:

```sh
opencode-guardrails
```

It respects an existing `OPENCODE_CONFIG_DIR` so project- or environment-specific overrides can still replace the packaged profile when needed.

## Managed deployment

Copy [managed/opencode.json](/Users/teradakousuke/Developer/opencode/packages/guardrails/managed/opencode.json) into the system managed config directory:
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The README link to managed/opencode.json is an absolute path to a local machine ("/Users/..."), which will be broken for everyone else and in GitHub rendering. Use a repository-relative link (e.g. "managed/opencode.json" or "./managed/opencode.json") instead.

Suggested change
Copy [managed/opencode.json](/Users/teradakousuke/Developer/opencode/packages/guardrails/managed/opencode.json) into the system managed config directory:
Copy [managed/opencode.json](managed/opencode.json) into the system managed config directory:

Copilot uses AI. Check for mistakes.

- macOS: `/Library/Application Support/opencode/opencode.json`
- Linux: `/etc/opencode/opencode.json`
- Windows: `%ProgramData%\\opencode\\opencode.json`

For macOS MDM deployments, use the same keys in the `ai.opencode.managed` payload that OpenCode already reads through managed preferences.
30 changes: 30 additions & 0 deletions packages/guardrails/bin/opencode-guardrails
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/usr/bin/env node

const child = require("child_process")
const fs = require("fs")
const path = require("path")

function fail(msg) {
console.error(msg)
process.exit(1)
}

function bin() {
const file = require.resolve("opencode/package.json")
const root = path.dirname(file)
const json = JSON.parse(fs.readFileSync(file, "utf8"))
const rel = typeof json.bin === "string" ? json.bin : json.bin?.opencode
if (!rel) fail("Failed to resolve opencode bin from dependency")
return path.resolve(root, rel)
}

const dir = path.resolve(__dirname, "..", "profile")
process.env.OPENCODE_CONFIG_DIR ||= dir

const out = child.spawnSync(bin(), process.argv.slice(2), {
stdio: "inherit",
env: process.env,
})

if (out.error) fail(out.error.message)
process.exit(typeof out.status === "number" ? out.status : 1)
38 changes: 38 additions & 0 deletions packages/guardrails/managed/opencode.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"$schema": "https://opencode.ai/config.json",
"share": "disabled",
"server": {
"hostname": "127.0.0.1",
"mdns": false
},
"permission": {
"edit": "ask",
"task": "ask",
"webfetch": "ask",
"external_directory": "ask",
"bash": {
"*": "ask",
"rm -rf *": "deny",
"sudo *": "deny",
"curl * | sh*": "deny",
"wget * | sh*": "deny"
},
"read": {
"*": "allow",
"*.env": "deny",
"*.env.*": "deny",
"*.env.example": "allow",
"*id_rsa*": "deny",
"*id_ed25519*": "deny",
"*.pem": "deny",
"*.key": "deny",
"*.p12": "deny",
"*.pfx": "deny",
"*.cer": "deny",
"*.crt": "deny",
"*.der": "deny",
"*.kdbx": "deny",
"*credentials*": "deny"
}
}
}
Loading