Configuration

Three files cover most of what you'll touch: .claude/settings.json (hooks + workflow), .xcoder/merge-policy.yaml (merge gate), .xcoder/supervisor.yaml (notifications, post-v1).

.claude/settings.json

Lives at the repo root. Drives both Claude Code (for hooks) and xCoder (for workflow). The schema below is the subset xCoder uses — Claude Code adds many more keys.

workflow block

json
{
  "workflow": {
    "type": "spec-first",                  // 'spec-first' | 'trunk' | ...
    "gitFlow": "trunk",                    // currently informational
    "integrationBranch": "main",           // override default

    "commitDirectly": false,               // I-1, I-2 bypass — opt in to commits on integration
    "commitPerTask": true,
    "specsRequired": true,                 // I-5 — turn off to skip spec gate
    "branchPrefix": "feat/",               // single prefix
    "branchPrefixes": ["feat/", "fix/"],   // OR multiple; both forms accepted

    "qaLoop": {
      "enabled": true,
      "testLocally": true,
      "verifySpec": true,
      "diffReport": true
    }
  }
}

hooks block

xCoder ships four hooks. xc hooks deploy writes the right config; you can also paste the JSON manually:

json
{
  "hooks": {
    "SessionStart": [
      {
        "matcher": "startup",
        "hooks": [{
          "type": "command",
          "command": "node \"$CLAUDE_PROJECT_DIR\"/node_modules/@xcoder/xcoder/dist/cli/index.js 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
        }]
      }
    ]
  }
}

quality block

json
{
  "quality": {
    "minQaScore": 85,
    "requireSpecs": true,
    "requireTests": false,
    "thresholds": {
      "scopedSpecCoverage": 80,
      "scopedImplComplete": 70,
      "scopedTestCoverage": 60,
      "scopedQaScore": 80
    }
  }
}

.xcoder/merge-policy.yaml

Drives the merge gate. Maps zones (kernel / business / docs / scaffold) and shapes (refactor / feature / fix / chore / docs) to verdict thresholds and required evidence producers.

yaml
# .xcoder/merge-policy.yaml
zones:
  kernel:
    paths:
      - "packages/xcoder/src/{merge-gate,hooks,scanner}/**"
      - "packages/flow-engine/src/{engine,guards}.ts"
    require: human-review              # always escalate
  business:
    paths: ["apps/web/src/app/api/**", "packages/core/src/**"]
    require: gate-pass-or-human
  docs:
    paths: ["**/*.md", "apps/web/src/app/docs/**"]
    require: gate-pass

shapes:
  refactor: { evidence: [scope, zone, calibrate-delta] }
  feature:  { evidence: [scope, zone, owasp, preview-smoke, visual-diff] }
  fix:      { evidence: [scope, zone, calibrate-delta] }
  chore:    { evidence: [scope, zone] }
  docs:     { evidence: [scope] }

verdicts:
  thresholds:
    minScopeMatch: 0.85
    maxFindings: 5
    maxKernelChanges: 0

Tracked configs are NOT gitignored

Generated artifacts (verdicts, screenshots, calibrate baselines) live under .xcoder/ and are gitignored. But .xcoder/merge-policy.yaml and .xcoder/routes.json are tracked configs — intentionally not gitignored. The pattern is: your team's policy is shared; their machine state is not.

.xcoder/supervisor.yaml post-v1

Notification routing for autopilot's supervisor protocol. Lives at the repo root or, for global defaults, ~/.xcoder/supervisor.yaml.

yaml
# .xcoder/supervisor.yaml
notify:
  sms:
    adapter: x402-sms                  # 'twilio' | 'x402-sms' | 'silent'
    phone: "+1..."
    on: [blocked, error, long_running]
    throttle_minutes: 5
    fallback_to_desktop: true
    mode: api-key                      # 'api-key' | 'x402-wallet'
    apiKeyEnv: DIAL_ADMIN_API_KEY

defaults:
  task.completed: { channel: sms, suppress_if_obvious: true }
  task.blocked.question: { channel: sms, also: digest }
  budget.warning.daily: { channel: email }
  budget.exceeded: { channel: [sms, email] }
  self-improvement.opportunity: { channel: digest, frequency: weekly }

quiet_hours:
  start: "22:00"
  end: "07:00"
  except: [budget.exceeded, task.failed.escalated]

Environment variables

VariableEffect
XCODER_ALLOW_INTEGRATION_EDIT= 1 — bypass no-edit-on-integration for one shell invocation.
XCODER_SKIP_QA_GATE= 1 — bypass typecheck-must-pass-before-commit (typecheck) for one invocation.
XCODER_SKIP_ISSUE_REF= 1 — bypass commit-must-reference-issue for one invocation.
XCODER_AUTO_PR= 1 — session-end-pr-backstop auto-runs `gh pr create --fill`.
FLOW_EVENTS_PATHOverride the default events log path (testing).
CLAUDE_PROJECT_DIRSet by Claude Code; xCoder hooks read it as the project root.

Next