diff --git a/wiki/SCHEMA.md b/wiki/SCHEMA.md index 8119a41..2ec2241 100644 --- a/wiki/SCHEMA.md +++ b/wiki/SCHEMA.md @@ -81,7 +81,7 @@ Raw files carry `source_url`, `ingested` and `sha256`. The hash covers the body Add a tag here before you use it. - **Layers:** core, runtime, surface, gateway, serve, ossuary, cli, tui -- **Subsystems:** providers, tools, plugins, mcp, sessions, events, context, memory, skills, security +- **Subsystems:** providers, tools, plugins, mcp, sessions, events, context, memory, skills, security, config - **Games:** games, npc, play, editor, engines, content - **Comparisons:** hermes, ecosystem - **Meta:** decision, roadmap, process, docs, performance, research diff --git a/wiki/concepts/runtime-profile-session.md b/wiki/concepts/runtime-profile-session.md index 2dc6ad1..1503c58 100644 --- a/wiki/concepts/runtime-profile-session.md +++ b/wiki/concepts/runtime-profile-session.md @@ -1,7 +1,7 @@ --- title: Runtime / Profile / Session split created: 2026-09-23 -updated: 2026-09-23 +updated: 2026-10-05 type: concept tags: [core, runtime, npc, gateway] sources: [raw/audits/2026-09-23-core-engine-audit.md, raw/audits/2026-09-23-game-surface-audit.md, "#113"] @@ -30,4 +30,6 @@ confidence: medium **Prerequisites:** remove process-global state (docs root, log level, Ollama id counter), and add the [[event-envelope]]. +**Not the same as config profiles:** #117 shipped *config* profiles, named file layers under `~/.lich/profiles` chosen per CLI run ([[lich-config]]). The runtime Profile here is a per-session object inside one process and is not built yet. + Related: [[npc-memory-namespaces]], [[embedded-safety-profile]]. diff --git a/wiki/entities/lich-config.md b/wiki/entities/lich-config.md new file mode 100644 index 0000000..5969ab9 --- /dev/null +++ b/wiki/entities/lich-config.md @@ -0,0 +1,55 @@ +--- +title: Lich config layers (global, profile, project) +created: 2026-10-05 +updated: 2026-10-05 +type: entity +tags: [config, cli, security] +sources: ["#117", "#170", "#171", "#172"] +confidence: high +--- + +# Lich config layers + +How the CLI turns files into one config before `parse_agent_config`. The user docs are `docs/user-guide/cli.md` (Global config) and `docs/user-guide/profiles.md`. This page records the design and the reasons for it. + +## Layers + +Without `--config`, `load_layered_config` (`src/cli_config.ts:127@ab0f508`) merges, base first: + +1. **Global:** `~/.lich/config.json` (`src/cli_config.ts:44@ab0f508`). The legacy `~/.config/lich/config.json` is read only when the global file is absent, with a one-line note; nothing writes it. +2. **Profile:** `~/.lich/profiles/.json` (`src/cli_config.ts:89@ab0f508`), plus `.md` as `system_prompt` when it is not blank (`src/cli_config.ts:105@ab0f508`). +3. **Project:** `/.lich/config.json`. + +`--config ` replaces every layer, and combining it with `--profile` is an error. + +**Merge** (`merge_config_layers`, `src/cli_config.ts:175@ab0f508`): shallow, later layer wins per key. A later `providers` array replaces the earlier one and drops the earlier `models` unless the later layer sets its own, because role chains name providers. + +**Global and profile layers** (`global_layer`, `src/cli_config.ts:190@ab0f508`): `work_dir` and `session_dir` are ignored. Relative `plugins` paths resolve against the file's own directory (`~/.lich` or `~/.lich/profiles`), not the project. + +**Profile selection:** `--profile`, then `LICH_PROFILE`, then a `profile` key in the project file, then one in the global file (set by `lich profile use`, `src/cli_profile.ts:107@ab0f508`). The `profile` key is removed from the merged config. `LICH_PROFILE` is ignored when `--config` is given. + +**Work_dir = home:** the project file *is* `~/.lich/config.json`. It is not merged over itself, and a selected profile goes over it rather than under it. + +## Writers + +- `write_lich_config` (`src/cli_config.ts:277@ab0f508`) is the only writer of `.lich/config.json` files (project and global); profile JSON is written by `lich profile create` (`src/cli_profile.ts:101@ab0f508`). Create mode uses an exclusive open; update mode writes a temp file and renames it into place, keeping the file mode (`src/cli_config.ts:307@ab0f508`, #166). +- `lich init` writes the project file; `lich init --global` writes the global one, without `work_dir`/`session_dir` (`src/cli.ts:694@ab0f508`). +- The setup wizard runs only when no file exists anywhere in the chain. Its last question can save the answers globally; discovered project plugins then stay in the project file, or are stored absolute when the project file is the global file (`src/cli.ts:615@ab0f508`). +- `lich profile create` writes a profile through the wizard and never overwrites. `lich mcp` edits only the project file. + +## Guard + +File tools refuse `.lich/config.json` and `.lich/profiles/` for reads and writes (`src/tools/guard.ts:83@ab0f508`). `list_dir` and `disk_usage` check their root and skip denied entries (`file_tool_denied`, `src/tools/guard.ts:100@ab0f508`). With `work_dir` = home these paths are the global identity files. + +## Two kinds of "profile" + +- **Config profile (#117, shipped):** a named file layer chosen per CLI run. It holds any config keys, including identity and model. +- **Runtime Profile (#113 §2b, not built):** cheap, data-only, chosen per session inside one Runtime ([[runtime-profile-session]]). + +A config profile could later seed a runtime Profile, but today they are separate things. Name new code accordingly. + +## Errors + +`tui`, `chat`, `serve` and `gateway` give the "no model configured" hint only for that error. Others pass through as `lich : ` (`src/cli.ts:150@ab0f508`). The profile errors (`profile not found`, `profile already exists`) carry no absolute paths (`.cursor/review-rules.md`). `config not found` and `invalid config json` still name the file. + +Related: [[lich-tools-and-guardrails]], [[hermes-agent]] (its profiles are separate home directories; Lich layers files instead). diff --git a/wiki/entities/lich-tools-and-guardrails.md b/wiki/entities/lich-tools-and-guardrails.md index 4d11620..d5773ad 100644 --- a/wiki/entities/lich-tools-and-guardrails.md +++ b/wiki/entities/lich-tools-and-guardrails.md @@ -1,7 +1,7 @@ --- title: Lich tools, executor and guardrails created: 2026-09-23 -updated: 2026-10-04 +updated: 2026-10-05 type: entity tags: [tools, security, runtime] sources: [raw/audits/2026-09-23-core-engine-audit.md, raw/audits/2026-09-23-game-surface-audit.md, "#161", "#163"] @@ -32,7 +32,7 @@ It also: ## Guardrails (the "wards") -- **File tools:** realpath confinement to `work_dir`, and writes to `.lich/config.json` are denied. +- **File tools:** realpath confinement to `work_dir`. `.lich/config.json` and `.lich/profiles/` are denied for reads and writes, and `list_dir`/`disk_usage` skip them (`src/tools/guard.ts:83@ab0f508`, #172; see [[lich-config]]). - **Network tools:** an SSRF guard blocks private and loopback URLs unless `LICH_ALLOW_PRIVATE_URLS=1`, and redirects are re-checked. - **`terminal` is not sandboxed.** It runs `bash -lc` in `work_dir` with secret env vars scrubbed. The docs say this plainly. diff --git a/wiki/index.md b/wiki/index.md index 48d6dd9..d39e51e 100644 --- a/wiki/index.md +++ b/wiki/index.md @@ -1,7 +1,7 @@ --- title: Wiki index type: index -updated: 2026-10-04 +updated: 2026-10-05 --- # Lich Wiki: Index @@ -15,9 +15,10 @@ Start here. Read [SCHEMA.md](SCHEMA.md) for the conventions and [log.md](log.md) ## Entities: Lich subsystems - [[lich-agent-loop]]: `run_conversation` + `Agent`. A dependency-injected TAO loop. Its P0 gaps are that events aren't scoped to a run, there is no streaming, it has global state, and each agent is heavyweight. -- [[lich-providers]]: openai_compat, anthropic and ollama clients without SDKs, plus failover and per-role chains (`models.chat` / `models.compress`, #154). They have no streaming, `tool_choice` or cache_control, and ~150 lines of their helpers are duplicated. +- [[lich-providers]]: openai_compat, anthropic and ollama clients without SDKs, plus failover and per-role chains (`models.chat` / `models.compress`, #154). They have no streaming, `tool_choice` or cache_control; their shared HTTP/error helpers live in `providers/http.ts` (#165). - [[lich-tools-and-guardrails]]: builtins, an executor that never throws, and the wards. Known holes: `terminal` isn't sandboxed and hooks have no timeout; `tools_enabled` covers plugin tools since #161. - [[lich-plugins-and-hooks]]: tool-call hooks with veto, the gatekeeper's single gated `git_commit`, and (#157) per-plugin settings, granted model roles and a `before_llm_call` note hook. There is no `build_system_prompt` hook yet; a throwing `before_tool_call` blocks the call (#161), other hooks fail open. +- [[lich-config]]: global `~/.lich/config.json` < named profile < project file, shallow merge; `lich init --global`, `lich profile`, and file tools barred from `.lich/profiles` (#170–#172). - [[lich-sessions]]: JSONL phylacteries used as combat logs. There is no search, and gateway files are supersets of each other. - [[lich-mcp]]: an MCP client and catalog. Redot is a real entry and Godot has none. The code is spread over 21 micro-files. - [[lich-gateway]]: familiars routed into one shared Agent. The per-chat bus and read-only defaults make it a good hub. diff --git a/wiki/log.md b/wiki/log.md index 879b2b8..7a78502 100644 --- a/wiki/log.md +++ b/wiki/log.md @@ -40,3 +40,5 @@ Append-only. One line per action: `- YYYY-MM-DD | | `. Ops - 2026-10-04 update | #161 merged: tools_enabled filters plugin tools and git_commit, throwing before_tool_call blocks, last-turn tool calls not run; holes lists and index updated, code pinned at 029b7e8 | entities/lich-plugins-and-hooks.md, entities/lich-tools-and-guardrails.md, entities/lich-agent-loop.md, index.md - 2026-10-04 update | #163 merged: S-11 items (http_request status, .. guard, terminal_timeout_ms) moved out of open holes, pinned at 7001e31 | entities/lich-tools-and-guardrails.md - 2026-10-04 update | Roadmap map lists #113 children and related issues (#133 P0, #134 P1, #117 P2, #144, #148, #149); supersedes stale PR #135 | entities/roadmap-issues.md +- 2026-10-05 create | Config layers page after #170–#172: global < profile < project merge, writers, guard, and config profile vs runtime Profile; pinned at ab0f508 | entities/lich-config.md, index.md, SCHEMA.md (tag: config) +- 2026-10-05 update | Guardrails: file tools deny .lich/profiles (reads too) and list_dir/disk_usage skip it; runtime-profile-session notes the config-profile name clash; index providers line no longer claims duplicated helpers (#165) | entities/lich-tools-and-guardrails.md, concepts/runtime-profile-session.md, index.md