# Knowledge Layered Configuration And Runtime Settings

> 覆盖 Blade 的用户/项目/local/调用级配置合并、workspace 定向解析、运行时 Store 投影和字段持久化路由。 使用时机：新增配置字段、调整覆盖优先级、排查多项目配置串扰、修改模型/Provider/MCP/LSP/插件设置或 Web 设置保存。 不包含：权限决策与 Folder Trust 细节见 permissions-and-workspace-trust，Session 资源冻结见 workspace-resource-snapshots-and-project-instructions。 关键词：ConfigManager, ConfigService, FIELD_ROUTING_TABLE, RuntimeConfig, configActions, settings.local.json, BLADE_MODEL。

- Skill: `echovic/knowledge-layered-configuration-and-runtime-settings` (Agent Skill)
- Install (CLI): `npx skillmds@latest add echovic/knowledge-layered-configuration-and-runtime-settings`
- Raw SKILL.md: https://api.skillmd.com/api/skills/echovic/knowledge-layered-configuration-and-runtime-settings/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: echovic (https://skillmd.com/u/echovic)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/echovic/knowledge-layered-configuration-and-runtime-settings

---


## Module Structure

配置系统将启动读盘、内存投影和磁盘持久化拆成三个边界，并为非启动 workspace 提供按 source project 重建执行配置的专用入口。

### Directory Layout
- `packages/cli/src/config/ConfigManager.ts` — 多层读取、信任过滤、归一化、验证和 workspace 定向解析
- `packages/cli/src/config/ConfigService.ts` — 字段/作用域路由、防抖、原子写和并发协调
- `packages/cli/src/config/defaults.ts` — 完整默认配置与默认权限
- `packages/cli/src/config/types.ts` — `BladeConfig`、`RuntimeConfig` 和 Provider/权限类型
- `packages/cli/src/config/runtimeEnvironment.ts` — Session 环境变量名称和值校验
- `packages/cli/src/store/slices/configSlice.ts` — 启动进程内存配置投影
- `packages/cli/src/store/vanilla.ts` — 面向 TUI、Server 和命令的配置动作
- `packages/cli/src/server/routes/config.ts` — Web 公开配置投影与更新 API
- `packages/cli/web/src/store/ConfigStore.ts` — workspace 模型选择与权限模式状态
- `packages/cli/web/src/store/SettingsStore.ts` — 通用设置的乐观更新与失败回滚

### Key Entry Points
- `ConfigManager.initialize()` — 合并默认、用户、可信项目、local 和调用级设置
- `ConfigManager.loadWorkspaceModelConfig()` — 为目标 source project 重建模型与 Provider 配置
- `ConfigManager.loadWorkspaceRuntimeSettings()` — 为目标 source project 解析 env、Hook 开关、轮次和权限模式
- `ConfigService.save()` — 按字段元数据选择文件、scope 和合并策略
- `configActions().updateConfig()` — 先更新 Store，再持久化，失败时回滚内存

## API Surface

### ConfigManager
- `initialize(additionalSettings?)` — 生成启动进程的完整 `RuntimeConfig`
- `reload()` — 使用上次显式运行时覆盖重新读取配置
- `loadWorkspacePermissions(workspaceRoot, base)` — 去除启动项目私有规则并叠加目标 workspace 规则
- `loadWorkspaceModelConfig(workspaceRoot, base)` — 重建目标 workspace 的模型、Provider 与准入配置
- `loadWorkspaceRuntimeSettings(workspaceRoot, base)` — 重建目标 workspace 的执行环境和行为设置
- `loadWorkspaceMcpServers()` / `loadWorkspaceLspServers()` — 按目标 workspace 隔离可执行服务配置

### ConfigService
- `save(updates, options)` — 校验可持久化字段并路由到目标文件
- `flush()` — 立即提交所有防抖写入
- `appendLocalPermissionRule()` / `appendLocalPermissionDenyRule()` — 对目标 workspace 做原子追加去重
- `removePluginSetting()` — 从指定 scope 删除插件覆盖而非写入相反值

### Store Actions
- `configActions().updateConfig()` — 内存先行并在持久化失败时恢复快照
- `configActions().setPermissionMode()` — 仅更新本次运行状态
- `configActions().addModelWithProvider()` — 原子更新 catalog、模型和 Provider 配置

## Usage Examples

### 为 Session 重建目标 workspace 配置
```typescript
const modelResources = await resolveWorkspaceModelResources(hookConfigRoot, config);
const runtimeConfig: BladeConfig = {
  ...modelResources.config,
  permissions: await configManager.loadWorkspacePermissions(
    hookConfigRoot,
    modelResources.config.permissions
  ),
};
```

### 通过共享动作持久化 Web 配置
```typescript
const { updates, options } = parsed.data;
await configActions().updateConfig(updates, options);
```

## Gotchas
- `ConfigManager.initialize()` 捕获任意加载或验证错误后会重置全局模型目录并返回 `DEFAULT_CONFIG`；调用方看到的可能是“没有模型”而不是原始坏配置，诊断时必须检查启动日志 (`packages/cli/src/config/ConfigManager.ts`)
- 进程 Store 不是多 workspace 执行配置的权威来源；目标目录与启动 cwd 不同时，模型、MCP、LSP、权限和运行时设置必须分别从用户层与该目标项目重建 (`packages/cli/src/config/ConfigManager.ts`, `git:3549bb1e`)
- 跨 workspace 权限解析会先从传入 base 中剔除启动项目独有规则，再叠加目标项目规则；直接在 base 上追加会把服务器启动目录的本地授权泄漏给其他 Session (`packages/cli/src/config/ConfigManager.ts`, `packages/cli/tests/integration/config.test.ts`, `git:7b34bd7e`)
- `config.json` 与 `settings.json` 不共享统一的深合并语义：模型数组整体替换，Provider/MCP/LSP 和插件映射按键合并，permissions 数组追加去重，Hook/env 深合并 (`packages/cli/src/config/ConfigManager.ts`)
- `permissionMode` 可以从启动参数或可信 settings 进入运行时，但 `ConfigService` 明确拒绝持久化该字段；会话恢复依赖 Session metadata，不依赖写回配置文件 (`packages/cli/src/config/ConfigService.ts`, `packages/cli/src/store/vanilla.ts`)
- `ConfigService.save()` 对未知更新字段直接报错，但写现有文件时保留磁盘中的未知字段；这是输入契约严格、旧版本数据向前兼容的刻意组合 (`packages/cli/src/config/ConfigService.ts`)
- 防抖保存发生在 timer 回调内，失败只记录到 `lastSaveError` 而不会回抛到早先的 `save()` 调用；需要事务语义的权限决策和模型生命周期必须使用 `immediate: true` 或专用原子动作 (`packages/cli/src/config/ConfigService.ts`)
- 项目未信任时，项目层只能暴露 Hook 摘要并可设置 `disableAllHooks=true` 收紧行为；env、模型、MCP、permissionMode 和 allow 规则全部忽略 (`packages/cli/src/config/ConfigManager.ts`, `packages/cli/tests/unit/services/workspace-model-resources.test.ts`)
- Web 对指定 `workspacePath` 调用 `setCurrentModel()` 时只更新当前客户端选择，不写入启动项目全局配置；无 workspace 参数时才通过 `/configs` 持久化 (`packages/cli/web/src/store/ConfigStore.ts`)
- Web 模型发现使用递增 sequence 丢弃迟到响应；移除该保护会让项目 A 的慢响应覆盖已切换到项目 B 的模型列表 (`packages/cli/web/src/store/ConfigStore.ts`, `packages/cli/web/tests/store/ConfigStore.test.ts`)

## Architecture
- `ConfigManager` 只负责 bootstrap/read/normalize/validate，Zustand Store 是启动表面的内存状态，`ConfigService` 是唯一磁盘写入路由；业务代码不应直接修改 JSON 配置 (`packages/cli/src/config/ConfigManager.ts`, `packages/cli/src/config/ConfigService.ts`, `packages/cli/src/store/slices/configSlice.ts`)
- 配置优先级是默认值 < 用户 config/settings < 可信项目 config/settings < local settings < 显式 invocation/CLI；环境变量插值在合并和字符串清理后递归执行 (`packages/cli/src/config/ConfigManager.ts`)
- `resolveWorkspaceModelResources()` 在深复制配置后创建 Session 私有 `PiModelCatalog`；CredentialStore 可共享，但 Provider definitions、endpoint 和 fallback 注册不共享可变状态 (`packages/cli/src/agent/resources/WorkspaceModelResources.ts`)

## Decisions
- 模型凭据从 `models` 和 `modelProviders` 分离到 `auth.json`，旧字段会被验证器主动拒绝而不是静默迁移，避免 endpoint 与 credential 身份混淆 (`packages/cli/src/config/ConfigManager.ts`, `packages/cli/src/config/modelProviders.ts`, `git:311ba368`)
- 配置文件写入统一使用 per-file mutex、read-modify-write 和 `0600` 原子替换，既保留未知字段，也避免并发 UI、CLI 与审批写入互相覆盖 (`packages/cli/src/config/ConfigService.ts`)
- 插件来源策略采用 tighten-only 合并：项目层只能开启更严格布尔限制或缩小 allowlist，不能覆盖用户级限制 (`packages/cli/src/config/ConfigManager.ts`, `packages/cli/src/config/pluginSettings.ts`)

## Patterns
- 新增持久化字段时，以 `FIELD_ROUTING_TABLE` 为单一写入路由源，并同步 `BladeConfig`、`DEFAULT_CONFIG`、`validateConfig()` 和公开 API 投影 (`packages/cli/src/config/ConfigService.ts`, `packages/cli/src/config/types.ts`, `packages/cli/src/config/defaults.ts`)
- 涉及多个磁盘字段和运行时 catalog 的动作先保存完整内存快照，任何持久化失败都同时恢复 Store 与 catalog (`packages/cli/src/store/vanilla.ts`, `packages/cli/src/server/routes/provider.ts`)
- 配置中的字符串会递归 trim 并移除包裹反引号，随后 `$VAR`、`${VAR}` 和 `${VAR:-default}` 在嵌套对象与数组中统一展开 (`packages/cli/src/config/ConfigManager.ts`, `git:9513f0d2`)

## Consumer Analysis
- SessionRuntime 是最大消费者，按 source project 组合模型、MCP、LSP、权限和 Hook，再冻结到 Runtime (`packages/cli/src/agent/runtime/SessionRuntime.ts`)
- Server 路由通过 `configActions` 更新设置，并为多项目请求传入精确 workspace 身份 (`packages/cli/src/server/routes/`)
- 插件系统读取 workspace 启用状态与 tighten-only 来源策略，生命周期写入必须指定 scope (`packages/cli/src/plugins/`)
- MCP 与 LSP 不复用启动 Store 的项目层，分别调用 workspace 定向解析器 (`packages/cli/src/mcp/`, `packages/cli/src/lsp/`)
- Web Store 维护乐观 UI 状态、请求去重和失败回滚，但服务端配置仍是持久化权威 (`packages/cli/web/src/store/`)

