How to get xCoder running at 100% enforcement in the OWASP.WTF monorepo using the OpenCode GUI for local AI SWE Agent development.
- Request alpha access:
hello@decoperations.com(subject: "xCoder alpha access") - Clone + build:
git clone https://github.com/DecOperations/xCoder.WTF.git && pnpm install && pnpm install:local - Attach to OpenCode:
xc flow attach opencode - Refresh guidelines:
xc flow guidelines refresh - Boot OpenCode GUI → every tool call now passes through xCoder's kernel-level guardrails
- Node 20+ and pnpm 9+ (your repo uses
pnpm@9.15.4) - Alpha access to xCoder (private repo, invite-only until v1)
- OpenCode Desktop GUI installed locally
- gh CLI installed (for PR backstop automation)
xCoder v0.1 is not yet on npm. Install from the private source repo:
# Clone the xCoder monorepo (needs alpha access)
git clone https://github.com/DecOperations/xCoder.WTF.git /tmp/xcoder-src
cd /tmp/xcoder-src
pnpm install
pnpm install:local # builds and runs `npm link`
# Verify
xc --version # 0.1.0-alpha.0
xcoder --version # sameNote: The xc and xcoder binaries are aliases.
xCoder analyzes your repo structure to derive enforcement rules:
cd /path/to/OWASP.WTF
# Infer from package.json, tsconfig, git log, CLAUDE.md, etc.
xc flow guidelines refresh
# Review what was inferred
xc flow guidelines showExpected inferred rules for this monorepo:
Resolved guidelines
source inferred
cache file .xcoder/guidelines.cache.json
specify
required true
spec path specs/ | docs/
branched
off main
prefix feat/ | fix/ | docs/ | test/ | chore/
qa
typecheck pnpm run typecheck (turbo typecheck)
test pnpm run test (turbo test)
lint pnpm run lint (turbo lint)
prioritize
source github-issues
The repo .xcoder/guidelines.yaml file pins the inferred rules to match our commitlint and security standards:
# .xcoder/guidelines.yaml
specify:
specRequired: true
specPath: specs/
branched:
prefix: ['feat/', 'fix/', 'docs/', 'test/', 'chore/']
off: main
qa:
typecheck: pnpm run typecheck
test: pnpm run test
lint: pnpm run lint
# Pin conventional commit format (from commitlint.config.cjs)
commit:
conventional: true
types: ['feat', 'fix', 'docs', 'style', 'refactor', 'perf', 'test', 'chore']Config hierarchy: guidelines.yaml beats guidelines.cache.json beats defaults.
This is the critical step for OpenCode GUI enforcement:
# Writes .opencode/plugins/xcoder.ts
cd /path/to/OWASP.WTF
xc flow attach opencodeWhat this creates:
.opencode/
└── plugins/
└── xcoder.ts # OpenCode plugin that wires xCoder hooks
The plugin intercepts every tool invocation in the OpenCode GUI and routes it through xCoder's 15-invariant contract.
| Mode | Supported? | Notes |
|---|---|---|
| OpenCode GUI (Desktop) | ✅ Yes | Full interactive enforcement |
| OpenCode CLI (TUI) | Works for manual sessions | |
| OpenCode Autopilot | ❌ No | TUI never exits — use Claude Code or Codex for autopilot |
For 100% autonomous enforcement: Use xc autopilot with Claude Code or Codex CLI as the runtime:
# Autopilot requires Claude Code or Codex (not OpenCode)
xc autopilot start --goal "harden OWASP rule coverage"After xc init --migrate-from unicorn-dev, the .claude/settings.json uses xCoder hooks exclusively:
{
"version": "0.1.0",
"xcoder": true,
"techLevel": "strict",
"interactionLevel": "yolo",
"proactivityLevel": "autonomous",
"workflow": {
"type": "spec-first",
"gitFlow": "trunk",
"commitPerTask": true,
"qaLoop": {
"enabled": true,
"testLocally": true,
"verifySpec": true,
"diffReport": true
}
},
"quality": {
"minQaScore": 85,
"requireSpecs": true,
"requireTests": false
},
"hooks": {
"SessionStart": [
{
"matcher": "startup",
"hooks": [
{
"type": "command",
"command": "xc boot",
"timeout": 10
}
]
}
],
"PreToolUse": [
{
"matcher": "Edit|Write|MultiEdit|NotebookEdit|Bash",
"hooks": [
{
"type": "command",
"command": "node \"$CLAUDE_PROJECT_DIR\"/node_modules/@xcoder/xcoder/dist/hooks/branch-guard.js",
"timeout": 5
}
]
},
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "node \"$CLAUDE_PROJECT_DIR\"/node_modules/@xcoder/xcoder/dist/hooks/qa-before-commit.js",
"timeout": 35
},
{
"type": "command",
"command": "node \"$CLAUDE_PROJECT_DIR\"/node_modules/@xcoder/xcoder/dist/hooks/issue-ref-guard.js",
"timeout": 5
}
]
}
],
"Stop": [
{
"matcher": "*",
"hooks": [
{
"type": "command",
"command": "node \"$CLAUDE_PROJECT_DIR\"/node_modules/@xcoder/xcoder/dist/hooks/session-end-pr-backstop.js",
"timeout": 60
}
]
}
]
} {
"type": "command",
"command": "node \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/track-tool-calls.ts",
"timeout": 5
},
{
"type": "command",
"command": "node \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/qa-after-write.ts",
"timeout": 5
},
{
"type": "command",
"command": "node \"$CLAUDE_PROJECT_DIR\"/node_modules/@xcoder/xcoder/dist/hooks/qa-before-commit.js",
"timeout": 35
},
{
"type": "command",
"command": "node \"$CLAUDE_PROJECT_DIR\"/node_modules/@xcoder/xcoder/dist/hooks/issue-ref-guard.js",
"timeout": 5
}
]
}
],
"Stop": [
{
"matcher": "*",
"hooks": [
{
"type": "command",
"command": "node \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/track-tool-results.ts",
"timeout": 5
},
{
"type": "command",
"command": "node \"$CLAUDE_PROJECT_DIR\"/node_modules/@xcoder/xcoder/dist/hooks/session-end-pr-backstop.js",
"timeout": 60
}
]
}
]
} }
**Key merge points:**
- **SessionStart:** Unicorn boot runs first, then xCoder boot
- **PreToolUse:** xCoder branch guard runs before Unicorn tracking
- **PreToolUse Bash:** xCoder QA + issue-ref guards added alongside existing Unicorn hooks
- **Stop:** Unicorn results tracking + xCoder PR backstop
---
## Step 6: Configure Merge Gate Policy
Create `.xcoder/merge-policy.yaml` (already in repo) to enforce domain-specific rules:
```yaml
# .xcoder/merge-policy.yaml
zones:
kernel:
paths:
- "packages/cli/src/core/**"
- "packages/cli/src/orchestrator.ts"
- "packages/cli/src/adapters/**"
- "packages/cli/src/types.ts"
require: human-review # Security-critical: always human review
business:
paths:
- "apps/**"
- "packages/*/src/app/**"
require: gate-pass-or-human # App logic: gate or human
docs:
paths:
- "docs/**"
- "**/*.md"
require: gate-pass # Docs: auto-gate is fine
shapes:
refactor: { evidence: [scope, zone, calibrate-delta] }
feature: { evidence: [scope, zone, owasp, preview-smoke] }
fix: { evidence: [scope, zone, calibrate-delta] }
chore: { evidence: [scope, zone] }
docs: { evidence: [scope] }
verdicts:
thresholds:
minScopeMatch: 0.85
maxFindings: 5
maxKernelChanges: 0
Why this matters: Changes to packages/cli/src/core/ (the OWASP rule engine) always require human review. Doc changes can auto-pass.
Boot an OpenCode GUI session and test each invariant:
# 1. Start OpenCode GUI in the repo
cd /path/to/OWASP.WTF
# (launch OpenCode Desktop app, open this folder)| Test | Command | Expected Result |
|---|---|---|
| I-1: Edit on main | Try Write to any file while on main |
❌ BLOCKED by no-edit-on-integration |
| I-2: Commit on main | git commit -m "test" on main |
❌ BLOCKED |
| I-3: Branch without issue | git checkout -b feat/test |
|
| I-4: Bad branch prefix | git checkout -b random-name |
❌ BLOCKED by branch-prefix-must-match |
| I-5: Spec missing | Commit without spec file | ❌ BLOCKED (if specsRequired) |
| I-6: Typecheck failing | Commit with type errors | ❌ BLOCKED by typecheck gate |
| I-7: Bad commit format | git commit -m "bad message" |
❌ BLOCKED by conventional commit |
| I-8: Missing issue ref | git commit -m "feat: thing" |
❌ BLOCKED by issue-ref guard |
| I-9: No PR at session end | End session with commits, no PR |
# Hotfix on main
XCODER_ALLOW_INTEGRRATION_EDIT=1 git commit -m "fix: critical #123"
# WIP commit (skip typecheck)
XCODER_SKIP_QA_GATE=1 git commit -m "wip: oauth"
# Chore commit without issue
XCODER_SKIP_ISSUE_REF=1 git commit -m "chore: update deps"
# Auto-create PR on session end
export XCODER_AUTO_PR=1Every bypass emits a flow.bypass event to .xcoder/flow-events.jsonl with the reason and source.
Heavy verification (typecheck, tests) runs out-of-band, not in the synchronous hook:
# Before each commit cycle
xc qa typecheck # writes verdict for I-6
xc qa test # writes verdict for test gate
xc qa lint # writes verdict for lint gate
xc qa show # show current verdicts + ages
# Then commit (now allowed)
git commit -m "feat: add A10 logging scanner #142"Note: Verdicts expire after 5 minutes. Re-run xc qa after each round of edits.
To ensure xCoder is automatically active every time you open the OpenCode GUI:
The .opencode/plugins/xcoder.ts file created by xc flow attach opencode auto-loads when OpenCode starts. No manual step needed.
Add to your shell profile for convenience:
# ~/.zshrc or ~/.bashrc
export XCODER_AUTO_PR=1 # Auto-open PRs on session end
export XCODER_EVENTS_PATH="$HOME/.xcoder/flow-events.jsonl"Ensure your OpenCode workspace settings point to the repo root where .opencode/plugins/xcoder.ts lives.
On every session start, xCoder logs a boot event. Check it's working:
tail -f .xcoder/flow-events.jsonl | jq '{event: .type, phase: .phase}'Expected output on boot:
{"event": "flow.boot", "phase": "idle"}
{"event": "flow.transition", "phase": "scope"}┌─────────────────────────────────────────────────────────────┐
│ OpenCode GUI Desktop │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ User Input │───▶│ LLM Agent │───▶│ Tool Call │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │ │
└───────────────────────────────────────────────────┼─────────┘
│
┌───────────────────────────────▼─────────┐
│ .opencode/plugins/xcoder.ts │
│ ┌─────────────────────────────────────┐│
│ │ PreToolUse Hook (branch-guard) ││
│ │ PreToolUse Hook (qa-before-commit) ││
│ │ PreToolUse Hook (issue-ref-guard) ││
│ │ Stop Hook (session-end-pr-backstop)││
│ └─────────────────────────────────────┘│
│ │ │
│ ┌─────────▼──────────┐ │
│ │ FlowEngine │ │
│ │ (12 phases, │ │
│ │ 5 gates) │ │
│ └─────────┬──────────┘ │
└───────────────────┼─────────────────────┘
│
┌───────────────────▼─────────────────────┐
│ .xcoder/flow-events.jsonl │
│ (audit trail of all decisions) │
└─────────────────────────────────────────┘
Key principle: The guardrails are in the kernel (hooks), not in the prompt context. The LLM cannot "forget" or override them.
# Ensure npm global bin is in PATH
export PATH="$PATH:$(npm config get prefix)/bin"
# Or use the full path
node /tmp/xcoder-src/packages/xcoder/dist/cli/index.js --version- Verify
.opencode/plugins/xcoder.tsexists - Check OpenCode plugin settings → ensure plugins are enabled
- Restart OpenCode GUI completely
OpenCode's plugin API may not support PreToolUse hooks the same way as Claude Code. If enforcement is inconsistent:
Fallback: Use Claude Code CLI for full kernel enforcement:
xc i # interactive Claude Code with xCoderThe hook has a 35-second budget. For large monorepos:
# Pre-run typecheck before committing
xc qa typecheck
# The hook then reads the cached verdict instead of re-running- Requested alpha access from
hello@decoperations.com - Installed xCoder:
git clone ... && pnpm install && pnpm install:local - Verified install:
xc --version - Ran:
xc flow guidelines refresh - Reviewed:
xc flow guidelines show - Created:
.xcoder/guidelines.yaml(monorepo overrides) - Created:
.xcoder/merge-policy.yaml(security zone rules) - Attached to OpenCode:
xc flow attach opencode - Verified
.opencode/plugins/xcoder.tsexists - (Optional) Merged xCoder hooks into
.claude/settings.json - Tested all 9 invariants in OpenCode GUI
- Set
XCODER_AUTO_PR=1for automatic PR creation - Monitoring:
tail -f .xcoder/flow-events.jsonl
- Local Testing: Boot OpenCode GUI → run the test matrix above
- Team Rollout: Share
.xcoder/guidelines.yamland.xcoder/merge-policy.yaml(these are tracked in git) - CI Integration: Pipe
.xcoder/flow-events.jsonlto your observability stack - Autopilot (Future): When ready for 24/7 autonomous mode, switch to
xc autopilotwith Claude Code or Codex runtime
Built by: DecOperations · xCoder v0.1 alpha
Status: 11/15 invariants live · 4 kernel hooks shipped · OpenCode (interactive) supported