Skip to content

feat(bot): INITIAL_SETTINGS_PRESET env var to seed default settings#175

Merged
grinev merged 3 commits into
grinev:mainfrom
tobyrosen:feat/hide-run-footer
Jul 11, 2026
Merged

feat(bot): INITIAL_SETTINGS_PRESET env var to seed default settings#175
grinev merged 3 commits into
grinev:mainfrom
tobyrosen:feat/hide-run-footer

Conversation

@tobyrosen

@tobyrosen tobyrosen commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Description of changes

I run a few instances of this bot from .env configs, and I kept tripping over the run footer on fresh installs. The /settings menu from 0.22.0 (#171) handles it nicely at runtime, but there's no way to preset the default, so every new instance starts with the footer on until someone opens /settings and toggles it. When you deploy several bots from config, that's a manual step per bot per reinstall.

Following the review suggestion, this now adds an INITIAL_SETTINGS_PRESET env var instead of the original footer-only flag. It takes a JSON object and seeds the initial value for any /settings option (ttsMode, compactOutputMode, showThinkingContent, sendDiffFileAttachments, responseStreamingMode, showAssistantRunFooter). A persisted /settings choice still takes precedence: preset values fill in only where the user hasn't picked anything, so the runtime toggles keep working exactly as they do now.

Parsing is defensive: invalid JSON, unknown keys, or wrong value types log a warning and are ignored, so a bad preset never crashes the bot. With the variable unset, nothing changes and existing users see no difference.

The variable is documented in the README and .env.example, with tests for the parsing and the seeding behavior.

Closes issue (optional)

No open issue for this; #134 covered a different footer request and is already closed.

How it was tested

npm run lint, npm run build, and npm test all pass, including the new tests: preset applied on a fresh install, persisted settings.json values never overwritten, invalid JSON / unknown keys / wrong value types ignored with a warning. It's pure config parsing, nothing OS-sensitive.

Checklist

  • PR title follows Conventional Commits: <type>(<scope>)?: <description>
  • This PR contains one logically complete change
  • Branch is rebased on the latest main
  • I ran npm run lint, npm run build, and npm test
  • If this PR is OS-sensitive, behavior/limitations for Linux/macOS/Windows are described

@grinev

grinev commented Jul 2, 2026

Copy link
Copy Markdown
Owner

@tobyrosen thanks for PR. I don't understand the problem, you can hide message footer with /settings command for each install. When I added /settings command, I also wanted to clear .env from some values. If you add something like this, you need to add default values for all runtime settings for consistency. But I'm not sure it's nessesary feature. When you install OpenCode for example you can't set default values for everything in settings

@tobyrosen

Copy link
Copy Markdown
Contributor Author

@grinev Fair point on the consistency. I wasn't looking to set defaults for everything in settings, just clear the one churn we actually hit.

The issue: I run several bot instances off .env configs (one per session), and reinstalls happen. /settings works, but toggling it per-bot per-reinstall is a manual step we trip over every time. The env var just lets the default ship preset so fresh installs start clean.

Two potential options, your call:

  • Keep this PR scoped to just HIDE_RUN_FOOTER (it's the common noise pain): small, low-friction to review, and "env defaults for all runtime settings" can be a separate follow-up if you want the consistency.
  • Or I extend this PR to seed env defaults for all runtime settings in one pass: more work and a bigger review surface, but consistent in one go.

Happy to go either way. I should be able to push more today. Thanks!

@grinev

grinev commented Jul 2, 2026

Copy link
Copy Markdown
Owner

@tobyrosen I think this feature can exist in that way:
Add optional env var
INITIAL_SETTINGS_PRESET="
}
"ttsMode": "all",
"compactOutputMode": true,
"showThinkingContent": true,
"sendDiffFileAttachments": false,
"responseStreamingMode": "edit",
"showAssistantRunFooter": false
}
"
If you want you can implement it

@tobyrosen tobyrosen changed the title feat(bot): add HIDE_RUN_FOOTER env var to preset the run footer default feat(bot): INITIAL_SETTINGS_PRESET env var to seed default settings Jul 3, 2026
@tobyrosen

Copy link
Copy Markdown
Contributor Author

@grinev thanks for the design suggestion. I've reworked the PR to implement INITIAL_SETTINGS_PRESET. The var accepts a JSON object and seeds any /settings value at startup; keys already present in settings.json are never touched, so existing users see no change. Invalid JSON, unknown keys, and type mismatches all log a warning and fall back gracefully; no crash.

@grinev

grinev commented Jul 11, 2026

Copy link
Copy Markdown
Owner

Hi @tobyrosen, thanks for the rework — the preset approach looks good and the tests cover it well. I ran the checks locally and there's one blocking issue plus a couple of changes I'd like to request.

  1. Lint is failing (blocking)
    npm run lint fails with two no-console errors in src/config.ts (parseInitialSettingsPreset). Please replace the console.warn calls with logger.warn from ./utils/logger.js. The project uses the logger everywhere instead of raw console.*. Importing it here is safe — logger doesn't depend on config, so there's no cycle, and it works fine before the log file stream is set up.

  2. Fail fast on an invalid preset
    This one is a design change. At the moment, invalid JSON, a non-object value, unknown keys, and wrong value types are all logged and ignored. I'd like to flip this: if INITIAL_SETTINGS_PRESET can't be parsed or validated, the bot should refuse to start (throw) instead of silently continuing.
    The reason is that a silent ignore means the settings simply never apply, and the operator has no easy way to notice — which is basically the same "why is the footer still on?" problem this PR is meant to solve. A typo in a key name falls into the same category.
    So I'd suggest throwing on:

  • invalid JSON,
  • a value that isn't a JSON object (array, number, string, etc.),
  • unknown keys,
  • a value with the wrong type.
    That makes a broken preset loud and obvious at startup, instead of a silent no-op. The existing test cases for "invalid JSON / wrong type" can then be updated to assert that startup throws.
  1. Small one: test isolation
    In tests/app/stores/settings-store.test.ts, beforeEach doesn't clear INITIAL_SETTINGS_PRESET. If a developer happens to have it set in their shell, the existing default-value tests could break. Adding delete process.env.INITIAL_SETTINGS_PRESET to beforeEach would keep the suite stable.

With the lint fix in, this should be ready to merge. Thanks again for the contribution!

tobyrosen and others added 3 commits July 11, 2026 17:18
The assistant run footer (agent, provider/model, elapsed time) can be toggled at runtime from /settings, but there is no way to preset its default for headless or declarative (.env-based) deployments.

Add a HIDE_RUN_FOOTER boolean env var, read via the existing getOptionalBooleanEnvVar helper, that seeds the default for the showAssistantRunFooter setting. It defaults to false (footer shown), so behavior is unchanged unless the variable is set. The runtime /settings toggle still takes precedence and is persisted in settings.json.

Document the variable in README and .env.example, and add config and settings-store tests.
Replace HIDE_RUN_FOOTER with a single INITIAL_SETTINGS_PRESET env var
that accepts a JSON object and seeds any runtime /settings value on first
run. Only keys absent from settings.json are affected; settings the user
has already changed via /settings are left untouched.

Supported keys: ttsMode, compactOutputMode, showThinkingContent,
showAssistantRunFooter, responseStreamingMode, sendDiffFileAttachments.

Invalid JSON falls back to built-in defaults without crashing. Unknown
keys and type mismatches are logged as warnings and skipped.

Co-Authored-By: Toby Rosen <46664805+tobyrosen@users.noreply.github.com>
Review changes for grinev#175: invalid JSON or a non-object value now throw in
config.ts; unknown keys and wrong value types throw in
applyInitialSettingsPreset, so a broken preset aborts startup instead of
being silently ignored. Removes the no-console lint errors, clears
INITIAL_SETTINGS_PRESET in the settings-store test beforeEach, and
updates .env.example wording.
@tobyrosen tobyrosen force-pushed the feat/hide-run-footer branch from 289b881 to b72cf5e Compare July 11, 2026 10:35
@tobyrosen

Copy link
Copy Markdown
Contributor Author

@grinev Thanks for the review — all three items addressed, plus a rebase onto current main (the edge TTS provider had landed next to my insertion point in the provider list; resolved keeping both).

  1. Lint — the two console.warn calls are gone entirely. With fail-fast they became throws, so there was nothing left to log and no logger import needed.
  2. Fail fast — implemented as requested: invalid JSON and non-object values now throw in config.ts, and unknown keys / wrong value types throw in applyInitialSettingsPreset, so the bot refuses to start on any broken preset instead of silently ignoring it. Since the throw aborts startup before the settings rewrite, no partial preset state ever persists. .env.example wording updated to match.
  3. Test isolation — added delete process.env.INITIAL_SETTINGS_PRESET to the settings-store beforeEach.

One note on the config-level tests: the settings-store cases assert that startup throws (loadSettings rejects), but for the JSON/shape cases I exported parseInitialSettingsPreset and assert the throw on the function directly — asserting on the module import itself trips vitest's module runner (an import-evaluation error is reported as an unhandled test error even when caught), which destabilized the whole file. This keeps the suite stable while the startup path still goes through the same throwing code.

npm run lint clean, tsc clean, all 1106 tests green.

@grinev

grinev commented Jul 11, 2026

Copy link
Copy Markdown
Owner

@tobyrosen approved. Thanks for contribution!

@grinev grinev merged commit 5326d1f into grinev:main Jul 11, 2026
1 check passed
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.

2 participants