Skip to content

Add agent settings injection into guest VM#54

Merged
JAORMX merged 3 commits intomainfrom
jaosorior/inject-agent-settings
Mar 18, 2026
Merged

Add agent settings injection into guest VM#54
JAORMX merged 3 commits intomainfrom
jaosorior/inject-agent-settings

Conversation

@JAORMX
Copy link
Copy Markdown
Contributor

@JAORMX JAORMX commented Mar 17, 2026

Summary

  • Implement declarative, per-agent settings injection framework that copies host agent settings (rules, skills, commands, instructions, config files) into the guest rootfs before boot
  • Support all three agents: Claude Code (~/.claude/), Codex (~/.codex/), OpenCode (~/.config/opencode/)
  • Fix MCP config hooks to deep-merge server maps instead of replacing (preserves user MCP servers alongside sandbox-tools)
  • Add --no-settings CLI flag, settings_import config section, and tighten-only workspace merge semantics

Architecture

Follows strict DDD — zero layer violations confirmed by review:

Layer New Files
Domain pkg/domain/settings/settings.go, filter.go — pure types, interfaces, constants
Infrastructure internal/infra/settings/injector.go, jsonc.go — FSInjector with O_NOFOLLOW, path containment, field filtering
Infrastructure internal/infra/vm/settingshook.go — rootfs hook (mirrors credentialhook.go)
Application pkg/sandbox/sandbox.goresolveSettingsManifest with category filtering
Composition cmd/bbox/main.go, pkg/runtime/factory.go — wiring

Security

  • Allowlist-only field filtering for MergeFile entries (deny-by-default for new config keys)
  • DenySubKeys strip secrets from MCP server configs (*.env, *.headers, *.token, etc.)
  • O_NOFOLLOW reads prevent TOCTOU symlink attacks (matching credential store pattern)
  • Source + destination path containment with filepath.EvalSymlinks
  • Tighten-only merge from workspace .broodbox.yaml (can only disable, never enable)
  • Size limits: 1 MiB/file, 50 MiB aggregate, 500 files, 8 depth

Hook Ordering

1. SSH keys + init binary + env + git config
2. InjectCredentials  (creates base config files)
3. InjectSettings     (merges user settings on top)   ← NEW
4. InjectMCPConfig    (deep-merges sandbox-tools)

Adding a Future Agent

Only requires populating SettingsManifest in registry.go — no new code paths.

Test plan

  • task fmt — clean
  • task lint — 0 issues
  • task test — 26/26 packages pass (with race detector)
  • New tests: filter_test.go, settingshook_test.go, injector_test.go (file/dir/merge/JSONC/safety limits), config merge tests, MCP deep-merge edge cases
  • Manual: bbox claude-code with ~/.claude/settings.json, rules/, skills/ → verify files in guest
  • Manual: bbox claude-code --no-settings → verify no settings injected
  • Manual: bbox codex with ~/.codex/config.toml containing [auth] → verify auth stripped
  • Manual: Verify MCP servers from host .claude.json preserved alongside sandbox-tools

Closes #53

🤖 Generated with Claude Code

@JAORMX JAORMX force-pushed the jaosorior/inject-agent-settings branch from 4f47a2c to 70c12aa Compare March 17, 2026 11:29
Copy link
Copy Markdown
Contributor

@jhrozek jhrozek left a comment

Choose a reason for hiding this comment

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

let's talk about the gues/host trust boundary and whether we want to migrate all the settings, the code in general looks good.

JAORMX and others added 3 commits March 18, 2026 06:01
Implement a declarative, per-agent settings injection framework that
copies host agent settings (rules, skills, commands, instructions, and
config files) into the guest rootfs before boot. This ensures coding
agents inside the VM start with the user's customizations.

Key design decisions:
- Allowlist-only field filtering for MergeFile entries (deny-by-default)
- Tighten-only merge from workspace config (can only disable, never enable)
- O_NOFOLLOW reads and source/destination path containment with EvalSymlinks
- Hook ordering: credentials → settings → MCP config (deep-merge preserves
  user MCP servers alongside sandbox-tools)

Closes #53

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Update USER_GUIDE.md, ARCHITECTURE.md, and CLAUDE.md with settings
injection documentation. Remove host MCP server configs from all agent
manifests — the VM cannot reach host MCP servers, only the toolhive-
proxied sandbox-tools endpoint should be present.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove hooks, bypassPermissions, enableAllProjectMcpServers from
  claude-code AllowKeys (security: no arbitrary command execution or
  permission bypass from host settings)
- Make applyDenySubKeys recursive so *.apiKey strips nested API keys
  at all depths, not just immediate children
- Bound deepMerge recursion by settings.MaxDepth to prevent stack
  overflow from pathologically nested configs
- Add nil guard for injector parameter in InjectSettings hook
- Pass logger from FSInjector to bestEffortChown instead of using
  package-level slog
- Add 31 tests covering stripKeyRecursive, deepMerge/deepMergeN,
  and applyDenySubKeys (including end-to-end nested key stripping)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@JAORMX JAORMX force-pushed the jaosorior/inject-agent-settings branch from 70c12aa to 5ca9f92 Compare March 18, 2026 04:13
@JAORMX JAORMX enabled auto-merge (squash) March 18, 2026 07:08
@JAORMX JAORMX merged commit 94d592f into main Mar 18, 2026
7 checks passed
@JAORMX JAORMX deleted the jaosorior/inject-agent-settings branch March 18, 2026 10:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Inject host agent settings into guest VM

2 participants