Skip to content

Commit 5dab8f6

Browse files
committed
fix(config): show resolved paths and redact secrets in config show
config show was displaying raw config defaults (~/...) instead of actual resolved paths, hiding the effect of LOCALGPT_PROFILE. Now all path fields (workspace, embedding_cache_dir, logging) are overridden with resolved values before display, and a resolved paths header is printed. API keys and secrets are redacted to "***". Also renames logging.file to logging.path (with serde alias for backwards compat) since it points to a directory, not a file — actual logs are date-rotated as localgpt-YYYY-MM-DD.log. Fixes incorrect LOCALGPT_PROFILE path format in docs (was workspace-{profile}, actual is localgpt-{profile}/workspace). Enables blog indexing for search.
1 parent f0370bb commit 5dab8f6

7 files changed

Lines changed: 80 additions & 19 deletions

File tree

config.example.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -324,5 +324,5 @@ policy = "deny"
324324
# Log level: trace, debug, info, warn, error
325325
level = "info"
326326

327-
# Log file path
328-
file = "~/.local/state/localgpt/logs/agent.log"
327+
# Log directory (logs are written as localgpt-YYYY-MM-DD.log)
328+
path = "~/.local/state/localgpt/logs"

crates/cli/src/cli/config.rs

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,16 +55,39 @@ pub async fn run(args: ConfigArgs) -> Result<()> {
5555
}
5656

5757
fn show_config(format: &str) -> Result<()> {
58-
let config = Config::load()?;
58+
let mut config = Config::load()?;
59+
60+
// Show resolved paths first (these account for LOCALGPT_PROFILE and env overrides)
61+
println!("# Resolved paths");
62+
println!("# config: {}", config.paths.config_dir.display());
63+
println!("# data: {}", config.paths.data_dir.display());
64+
println!("# workspace: {}", config.paths.workspace.display());
65+
println!("# state: {}", config.paths.state_dir.display());
66+
println!("# cache: {}", config.paths.cache_dir.display());
67+
println!("# logs: {}", config.paths.logs_dir().display());
68+
if let Some(ref rt) = config.paths.runtime_dir {
69+
println!("# runtime: {}", rt.display());
70+
}
71+
println!();
72+
73+
// Replace raw config values with resolved paths so output is accurate
74+
config.memory.workspace = config.paths.workspace.display().to_string();
75+
config.memory.embedding_cache_dir = config
76+
.paths
77+
.cache_dir
78+
.join("embeddings")
79+
.display()
80+
.to_string();
81+
config.logging.path = config.paths.logs_dir().display().to_string();
5982

6083
match format {
6184
"json" => {
6285
let json = serde_json::to_string_pretty(&config)?;
63-
println!("{}", json);
86+
println!("{}", redact_secrets(&json));
6487
}
6588
_ => {
6689
let toml = toml::to_string_pretty(&config)?;
67-
println!("{}", toml);
90+
println!("{}", redact_secrets(&toml));
6891
}
6992
}
7093

@@ -114,6 +137,44 @@ fn init_config(force: bool) -> Result<()> {
114137
Ok(())
115138
}
116139

140+
/// Redact secret values in serialized config output.
141+
/// Matches lines where the key contains "api_key", "api_token", "secret", or
142+
/// "service_account_key" and replaces the value with "***".
143+
fn redact_secrets(output: &str) -> String {
144+
const SECRET_KEYS: &[&str] = &[
145+
"api_key",
146+
"api_token",
147+
"secret",
148+
"service_account_key",
149+
"auth_token",
150+
];
151+
152+
output
153+
.lines()
154+
.map(|line| {
155+
let trimmed = line.trim_start();
156+
// TOML: key = "value" or JSON: "key": "value"
157+
for key in SECRET_KEYS {
158+
// TOML format: api_key = "..."
159+
if trimmed.starts_with(key) && trimmed.contains("= \"") {
160+
if let Some(eq_pos) = line.find("= \"") {
161+
return format!("{}= \"***\"", &line[..eq_pos]);
162+
}
163+
}
164+
// JSON format: "api_key": "..."
165+
let json_key = format!("\"{}\":", key);
166+
if trimmed.starts_with(&json_key) && trimmed.contains('"') {
167+
if let Some(colon_pos) = line.find(':') {
168+
return format!("{}: \"***\"", &line[..colon_pos]);
169+
}
170+
}
171+
}
172+
line.to_string()
173+
})
174+
.collect::<Vec<_>>()
175+
.join("\n")
176+
}
177+
117178
const DEFAULT_CONFIG_TEMPLATE: &str = r#"# LocalGPT Configuration
118179
119180
[agent]

crates/core/src/config/mod.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -813,8 +813,8 @@ pub struct LoggingConfig {
813813
#[serde(default = "default_log_level")]
814814
pub level: String,
815815

816-
#[serde(default = "default_log_file")]
817-
pub file: String,
816+
#[serde(default = "default_log_path", alias = "file")]
817+
pub path: String,
818818

819819
/// Days to keep log files (0 = keep forever, no auto-deletion)
820820
#[serde(default)]
@@ -1091,8 +1091,8 @@ fn default_bind() -> String {
10911091
fn default_log_level() -> String {
10921092
"info".to_string()
10931093
}
1094-
fn default_log_file() -> String {
1095-
format!("{}/logs/agent.log", DEFAULT_STATE_DIR_STR)
1094+
fn default_log_path() -> String {
1095+
format!("{}/logs", DEFAULT_STATE_DIR_STR)
10961096
}
10971097
fn default_sandbox_level() -> String {
10981098
"auto".to_string()
@@ -1237,7 +1237,7 @@ impl Default for LoggingConfig {
12371237
fn default() -> Self {
12381238
Self {
12391239
level: default_log_level(),
1240-
file: default_log_file(),
1240+
path: default_log_path(),
12411241
retention_days: 0, // 0 = keep forever
12421242
}
12431243
}

website/docs/configuration.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -268,8 +268,8 @@ disable_suffix = false
268268
# Log level: trace, debug, info, warn, error
269269
level = "info"
270270

271-
# Log file path
272-
file = "~/.local/state/localgpt/logs/agent.log"
271+
# Log directory (logs are written as localgpt-YYYY-MM-DD.log)
272+
path = "~/.local/state/localgpt/logs"
273273

274274
#──────────────────────────────────────────────────────────────────────────────
275275
# Telegram Bot
@@ -535,14 +535,14 @@ LocalGPT supports multiple workspaces via environment variables (OpenClaw-compat
535535
export LOCALGPT_WORKSPACE=~/my-project/ai-workspace
536536
localgpt chat
537537

538-
# Use profile-based workspaces
539-
export LOCALGPT_PROFILE=work # uses ~/.local/share/localgpt/workspace-work
540-
export LOCALGPT_PROFILE=home # uses ~/.local/share/localgpt/workspace-home
538+
# Use profile-based isolation (all directories get -profile suffix)
539+
export LOCALGPT_PROFILE=work # uses ~/.local/share/localgpt-work/workspace
540+
export LOCALGPT_PROFILE=home # uses ~/.local/share/localgpt-home/workspace
541541
```
542542

543543
Resolution order:
544544
1. `LOCALGPT_WORKSPACE` env var (absolute path override)
545-
2. `LOCALGPT_PROFILE` env var (creates `~/.local/share/localgpt/workspace-{profile}`)
545+
2. `LOCALGPT_PROFILE` env var (creates `~/.local/share/localgpt-{profile}/workspace`)
546546
3. `memory.workspace` from config file
547547
4. Default: `~/.local/share/localgpt/workspace`
548548

website/docs/heartbeat.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ Each heartbeat cycle follows this flow:
221221
## Logging
222222

223223
Heartbeat actions are logged to:
224-
- Application log (`~/.local/state/localgpt/logs/agent.log`)
224+
- Application log (`~/.local/state/localgpt/logs/localgpt-YYYY-MM-DD.log`)
225225
- Daily memory log (if memory_append is used)
226226

227227
## Best Practices

website/docs/intro.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ LocalGPT follows the [XDG Base Directory Specification](https://specifications.f
4141
4242
~/.local/state/localgpt/
4343
├── logs/
44-
│ └── agent.log # Application logs
44+
│ └── localgpt-YYYY-MM-DD.log # Daily application logs
4545
└── localgpt.audit.jsonl # Append-only audit log
4646
4747
~/.cache/localgpt/

website/docusaurus.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ const config: Config = {
4545
'@easyops-cn/docusaurus-search-local',
4646
{
4747
hashed: true,
48-
indexBlog: false,
48+
indexBlog: true,
4949
},
5050
],
5151
],

0 commit comments

Comments
 (0)