claude-code

User settings, operator-enforced managed settings, and MCP servers for the Claude Code CLI and its editor panels.

Configures Claude Code. Install it with the claude-code devtool.

toolconfigs:
  - id: claude-code
    name: claude-code
    config:
      managedSettings:
        permissions:
          defaultMode: bypassPermissions

config fields

FieldTypeDescription
settingsobjectThe user settings layer, written to ~/.claude/settings.json and owned by the login user. Unknown keys round-trip untouched.
managedSettingsobjectThe managed settings layer, written root-owned to /etc/claude-code/managed-settings.json. Highest precedence; survives user edits.
mcpServersobjectMCP servers to apply at user scope. See below.

The two settings layers mirror the soft/hard split Claude Code itself defines: settings is what a user may override, managedSettings is operator policy — the same file a corporate device-management policy would target, so the two compose.

Permissions default to bypass

Unless you say otherwise, Ringleader writes permissions.defaultMode: "bypassPermissions" into the managed layer. A workstation is the sandbox that Claude Code’s permission prompts exist to protect, so prompting inside one is friction with no safety gain.

This happens on install alone — a workstation with the claude-code devtool and no toolconfig still gets it.

Ringleader steps back if you have expressed an opinion. Setting either permissions.defaultMode or permissions.disableBypassPermissionsMode in managedSettings leaves your permissions block exactly as written. Any other keys in that block — allow, deny, ask — are preserved either way.

toolconfigs:
  - id: claude-code
    name: claude-code
    config:
      managedSettings:
        permissions:
          defaultMode: default        # opt out of bypass; prompts return
          deny:
            - "Bash(rm -rf *)"

The background auto-updater is off

Also on install alone, Ringleader writes env.DISABLE_AUTOUPDATER: "1" into the managed layer. Claude Code is installed globally as root and pinned to the version the recipe resolves, so the updater — which runs as the workstation user — cannot write that prefix, and would move the workstation off its pinned version if it could. All it produced was an Auto-update failed warning on the status line.

claude update still works as a manual escape hatch, and the declarative way to move a workstation is the devtool’s version.

The same operator-wins rule applies: set the key yourself and your value stands.

toolconfigs:
  - id: claude-code
    name: claude-code
    config:
      managedSettings:
        env:
          DISABLE_AUTOUPDATER: "0"    # opt back into background auto-update

MCP servers

mcpServers is a map of server name to definition. Ringleader does not write a file for these: it runs Claude Code’s own claude mcp add --scope user as the login user, so the servers land where the terminal CLI and the editor panels read them, and you can still add your own servers by hand.

FieldTypeDescription
typestringhttp, sse, or stdio. Defaults to stdio when command is set, otherwise http.
urlstringRequired for http and sse.
headersobjectHeader name to value, for http/sse. May carry secret references.
commandstringRequired for stdio.
argsarray of stringArguments for stdio.
envobjectEnvironment for a stdio server. May carry secret references.
toolconfigs:
  - id: claude-code
    name: claude-code
    config:
      mcpServers:
        linear:
          type: http
          url: https://mcp.linear.app/mcp
        github:
          type: http
          url: https://api.githubcopilot.com/mcp/
          headers:
            Authorization: "Bearer ${secret:gh-token/token}"

Applying them is change-gated. It runs the first time the workstation sets itself up and again only when the desired server set changes, so tokens you obtained interactively (via /mcp in Claude) are never disturbed by a routine re-apply. When the set does change, each declared server is re-added, and any server Ringleader previously managed and you have since removed from the config is removed from the workstation. Servers you added yourself are never touched.

An empty mcpServers: {} is a valid declaration: “manage zero servers”, which still removes the ones Ringleader previously added.

Servers arrive unauthenticated

Declaring an MCP server does not authenticate it. Unless you supply a header or environment token, run /mcp in Claude and authenticate in the browser. Pair with passthrough-www-browser to have that page open on your laptop.

Workspace trust

Folders in sources[].path and trustedFolders are pre-trusted for the CLI, so it never opens with a trust prompt on the code the workstation exists to work on. Ringleader merges the trust flags into Claude’s own state file rather than overwriting it, and a folder that is already trusted is left completely alone.

Example

The full picture — a workstation whose terminal claude and editor panel both open in bypass mode, with an MCP server wired up:

apiVersion: workstations.ringleader.dev/v1
kind: WorkstationConfig
metadata:
  name: ai-box
  namespace: local
spec:
  selector:
    matchLabels:
      tier: dev
  identity:
    user: dev
    shell: /bin/bash
  devtools:
    - name: nodejs
      version: "24"
    - name: claude-code
    - name: vscode-web
    - name: passthrough-www-browser
  toolconfigs:
    - id: claude-code
      name: claude-code
      config:
        mcpServers:
          linear:
            type: http
            url: https://mcp.linear.app/mcp
        managedSettings:
          permissions:
            defaultMode: bypassPermissions
  sources:
    - name: app
      git:
        url: https://github.com/acme/app.git
        ref: main
      path: /home/dev/src/app         # pre-trusted
  defaultLocalBinding:
    enabled: true
    autoForward:
      forwardAll: true
    urlForward:
      enabled: true
      open: true

Notes

  • A mcpServers entry needs the claude CLI on the workstation. Declare the claude-code devtool; without it, the apply step fails loudly.
  • Secret-bearing headers and environment values are passed to Claude through the environment, never written into a script or a diagnostic record.
  • Editor panels ignore the CLI’s managed settings. To set panel behaviour, use the vscode-web or vscode-server toolconfig.