Summary
For a TutorBot with auto_start: true, setting allow_shell_exec: true in its config.yaml has no effect: the flag is silently overwritten back to false on every backend startup. As a result the shell exec tool is never registered for auto-started bots, and anything that depends on it (e.g. the built-in notebook skill, which shells out to deeptutor notebook ...) is unusable.
Environment
- DeepTutor v1.4.2 (commit
c4d4766)
- Self-hosted backend (systemd-managed), single user
Root cause
TutorBotManager.auto_start_bots() rebuilds BotConfig from disk but omits allow_shell_exec:
# deeptutor/services/tutorbot/manager.py — auto_start_bots() (~L977)
config = BotConfig(
name=data.get("name", bid),
description=data.get("description", ""),
persona=data.get("persona", ""),
channels=data.get("channels", {}),
model=data.get("model"),
llm_selection=data.get("llm_selection"),
) # <-- allow_shell_exec missing -> defaults to False
await self.start_bot(bid, config)
BotConfig.allow_shell_exec defaults to False, so the instance starts with exec disabled. start_bot() then persists that (false) config at the end:
# deeptutor/services/tutorbot/manager.py — start_bot() (~L529)
self.save_bot_config(bot_id, config)
So on every boot: auto_start_bots builds a config without the flag → starts the bot with exec disabled → writes allow_shell_exec: false back to config.yaml, clobbering the admin's setting.
The on-demand start path is correct — load_bot_config() reads the flag:
# deeptutor/services/tutorbot/manager.py — load_bot_config() (~L351)
allow_shell_exec=_strict_config_bool(data.get("allow_shell_exec", False)),
so chat-triggered lazy start (_ensure_running_bot / WebSocket) honors it. Only auto_start_bots() drops it.
Reproduction
- Create a TutorBot (it is persisted with
auto_start: true).
- Stop the backend; set
allow_shell_exec: true in data/tutorbot/<bot_id>/config.yaml.
- Start the backend.
- Inspect
config.yaml → it is allow_shell_exec: false again; the exec tool is not registered.
Contrast: set auto_start: false + allow_shell_exec: true, then restart → the flag survives (because auto_start_bots skips the bot and the lazy-start path uses load_bot_config). This confirms the defect is specifically in the auto-start path.
Expected
allow_shell_exec set in config.yaml should be honored for auto-started bots and must never be silently overwritten.
Suggested fix
Include the flag in the BotConfig built by auto_start_bots() (mirroring load_bot_config):
allow_shell_exec=_strict_config_bool(data.get("allow_shell_exec", False)),
Alternatively, have auto_start_bots() reuse load_bot_config(bid) instead of re-constructing BotConfig inline, which would prevent this whole class of field-drift bugs.
Summary
For a TutorBot with
auto_start: true, settingallow_shell_exec: truein itsconfig.yamlhas no effect: the flag is silently overwritten back tofalseon every backend startup. As a result the shellexectool is never registered for auto-started bots, and anything that depends on it (e.g. the built-innotebookskill, which shells out todeeptutor notebook ...) is unusable.Environment
c4d4766)Root cause
TutorBotManager.auto_start_bots()rebuildsBotConfigfrom disk but omitsallow_shell_exec:BotConfig.allow_shell_execdefaults toFalse, so the instance starts with exec disabled.start_bot()then persists that (false) config at the end:So on every boot:
auto_start_botsbuilds a config without the flag → starts the bot with exec disabled → writesallow_shell_exec: falseback toconfig.yaml, clobbering the admin's setting.The on-demand start path is correct —
load_bot_config()reads the flag:so chat-triggered lazy start (
_ensure_running_bot/ WebSocket) honors it. Onlyauto_start_bots()drops it.Reproduction
auto_start: true).allow_shell_exec: trueindata/tutorbot/<bot_id>/config.yaml.config.yaml→ it isallow_shell_exec: falseagain; the exec tool is not registered.Contrast: set
auto_start: false+allow_shell_exec: true, then restart → the flag survives (becauseauto_start_botsskips the bot and the lazy-start path usesload_bot_config). This confirms the defect is specifically in the auto-start path.Expected
allow_shell_execset inconfig.yamlshould be honored for auto-started bots and must never be silently overwritten.Suggested fix
Include the flag in the
BotConfigbuilt byauto_start_bots()(mirroringload_bot_config):Alternatively, have
auto_start_bots()reuseload_bot_config(bid)instead of re-constructingBotConfiginline, which would prevent this whole class of field-drift bugs.