diff --git a/crates/botloftd/src/supervisor/spawn.rs b/crates/botloftd/src/supervisor/spawn.rs
index f39b5d6d..84f89e1c 100644
--- a/crates/botloftd/src/supervisor/spawn.rs
+++ b/crates/botloftd/src/supervisor/spawn.rs
@@ -23,6 +23,9 @@ use crate::{approvals, context, courier, routines, workspace};
/// Tools the bot uses without asking: its crew tools (spec 7.4).
const ALLOWED_TOOLS: &str = "mcp__botloft";
+/// Claude Code's own schedulers: they die with the process and Botloft never
+/// sees them. Work at set times is a routine (spec 7.4, 20).
+const DISALLOWED_TOOLS: &str = "CronCreate,CronDelete,CronList,ScheduleWakeup,RemoteTrigger";
/// Makes Claude Code load `CLAUDE.md` from `--add-dir` folders (spec 5).
const ADDITIONAL_MEMORY: &str = "CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD";
/// Where permission requests go (spec 10.1).
@@ -220,6 +223,8 @@ fn launch_spec(
PERMISSION_TOOL,
"--allowedTools",
ALLOWED_TOOLS,
+ "--disallowedTools",
+ DISALLOWED_TOOLS,
"--mcp-config",
] {
args.push(arg.into());
diff --git a/crates/botloftd/src/workspace/files.rs b/crates/botloftd/src/workspace/files.rs
index 7e77f149..9ea7cadc 100644
--- a/crates/botloftd/src/workspace/files.rs
+++ b/crates/botloftd/src/workspace/files.rs
@@ -128,6 +128,9 @@ app; the other bots of your crew send you messages too.
writes to you in, that says what the command does and why you need it,
in everyday words, with no code, file paths or jargon. They read it to
decide whether to allow the command.
+- You cannot schedule work yourself. When the owner wants something done at
+ set times, ask them to create a routine in your Routines tab in the
+ Botloft app. Never say it is scheduled until a routine exists.
## Working with your crew
@@ -264,6 +267,7 @@ mod tests {
assert!(rules.contains("attachments/"));
assert!(rules.contains("fill in its\n `description` for them"));
assert!(rules.contains("`browser_*` tools"));
+ assert!(rules.contains("create a routine in your Routines tab"));
assert!(rules.contains(r#""#));
assert!(!rules.contains("You lead this crew"));
diff --git a/crates/botloftd/tests/supervisor.rs b/crates/botloftd/tests/supervisor.rs
index d3beedb5..07cc70be 100644
--- a/crates/botloftd/tests/supervisor.rs
+++ b/crates/botloftd/tests/supervisor.rs
@@ -63,6 +63,10 @@ async fn a_new_bot_runs_headless_in_a_new_session_with_a_clean_environment() {
arg_after(&process, "--allowedTools").as_deref(),
Some("mcp__botloft")
);
+ assert_eq!(
+ arg_after(&process, "--disallowedTools").as_deref(),
+ Some("CronCreate,CronDelete,CronList,ScheduleWakeup,RemoteTrigger")
+ );
assert!(arg_after(&process, "--mcp-config").is_some_and(|path| path.ends_with("mcp.json")));
assert!(process.spec.cwd.ends_with("scout"));
assert_eq!(
diff --git a/docs/spec.md b/docs/spec.md
index 3b97d90f..a232cbb4 100644
--- a/docs/spec.md
+++ b/docs/spec.md
@@ -131,7 +131,7 @@ O **handle** do bot (`@revisao`) é derivado do nome pela mesma regra, acompanha
attachments\\ arquivos que o dono mandou no chat (9.5)
.claude\
settings.json regra de negação para os segredos e o que o Claude Code não carrega no bot, 7.5 (gerado pelo daemon, sobrescrito a cada start)
- rules\botloft.md identidade, papel, crew, pasta de trabalho, guia de uso das tools, como explicar cada comando ao dono (10.1) e, no chefe, como liderar (gerado pelo daemon)
+ rules\botloft.md identidade, papel, crew, pasta de trabalho, guia de uso das tools, como explicar cada comando ao dono (10.1), que agendar é rotina (20) e, no chefe, como liderar (gerado pelo daemon)
.botloft\
mcp.json config MCP do bot (gerado pelo daemon)
```
@@ -244,10 +244,12 @@ Eventos de uma generation antiga são ignorados. Todo processo novo emite `bot.s
[--effort ]
--permission-prompt-tool mcp__botloft__permission_prompt
--allowedTools mcp__botloft
+ --disallowedTools CronCreate,CronDelete,CronList,ScheduleWakeup,RemoteTrigger
```
- `--setting-sources project,local` e `--strict-mcp-config` deixam de fora hooks, skills, agents, modo de permissão e servidores MCP pessoais do dono: o bot vê o que o Botloft gera. O login da conta não é uma fonte de settings e continua valendo. As instruções pessoais do dono (`%USERPROFILE%\.claude\CLAUDE.md`) não saem por essa flag: o Claude Code as acha subindo as pastas a partir do cwd. Quem as deixa de fora, junto com a memória automática, é o `settings.json` gerado (7.5).
- `--allowedTools mcp__botloft` libera as tools da crew sem aprovação. Uma regra `allow` no `settings.json` do projeto não bastaria: em `-p`, numa pasta que nunca passou pelo diálogo de confiança, o Claude Code não aplica as regras `allow` do projeto (documentado em `permissions`).
+ - `--disallowedTools` tira do bot os agendamentos do próprio Claude Code. `CronCreate` e `ScheduleWakeup` só valem enquanto aquele processo vive: somem num reinício, expiram em 7 dias, e o Botloft não os vê nem os mostra. `RemoteTrigger` cria agendamentos na nuvem, fora do computador. Pedido para agendar, um bot usava `CronCreate` sem pedir permissão e dizia que tinha agendado (19). Trabalho em horário marcado é uma rotina (20).
- Qualquer outra ferramenta que peça permissão passa pela tool de aprovação (10.1) e vira um pedido no chat.
- `--add-dir` põe a pasta de trabalho da crew (5) entre as pastas do bot. Sem ela, gravar na `shared\`, que fica fora do workspace, pedia aprovação até em "Aceitar edições" (19).
- `--permission-mode` vem do modo do bot (`Bot.permissionMode`), que o dono escolhe no chat (15.1): `default` (Manual: pergunta antes de editar, rodar comandos e usar a rede), `accept_edits` (`acceptEdits`: edita arquivos sem perguntar), `plan` (planeja e pede para seguir, 10.1), `auto` (um classificador libera o que é seguro e o resto vira pedido) e `bypass_permissions` (`bypassPermissions`: faz tudo sem perguntar, ver 13). Bot novo começa em `default`. `dontAsk` não é oferecido: nega o que não estiver liberado, e o bot não teria como pedir. Regras `deny` valem em todos os modos.
@@ -961,6 +963,7 @@ Conferência na documentação oficial (code.claude.com/docs) em 2026-09-28; esf
| Prévia de PDF no painel de arquivos | 15.1 | O PDF vai para um `