Compare commits

...
3 Commits
Author SHA1 Message Date
pastilhasandClaude Opus 5 3f873fe4c2 regenerate: /todos left for the kanban plugin
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-29 03:29:59 +01:00
pastilhasandClaude Opus 5 79acaa5eb9 regenerate: /user joins the owner-only broadcast routes
real drift, and the only thing left in the diff once the generator stopped
rewriting `name` back to a label. the platform gained an owner-only `/user`
broadcast route and this had not caught up.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-29 01:35:30 +01:00
pastilhasandClaude Opus 5 a57cb1b19d a skill for bots, which had none
the bot's OWN brief is thorough and lives in the bots directory, rewritten every
turn. what was missing is the doc for everyone else: what a bot is, where it
lives, why it has not fired, and how it differs from a commander.

the line is not size. one thing watched and one action is a bot; anything that
has to remember what it already handled is a commander. the bot brief tells bots
not to read the commander skill for exactly that reason.

carries the thing that is easy to lose: <sessionId>.bot.json is the ONLY link
between a conversation and a detached shell pid. a bot deleted on 2026-08-26 was
still polling a website eleven minutes later because that file did not exist yet.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 16:43:03 +01:00
2 changed files with 91 additions and 3 deletions
+90
View File
@@ -0,0 +1,90 @@
---
name: bots
title: Bots
description: >-
Use when the owner asks about a bot — what one is, how to start one, why one has not fired, how to stop
one, or why it is a bot rather than a commander. Also read it before setting one up FOR them. Carries
where a bot lives, the record that is the only thing able to stop it, and the two ways one dies quietly.
version: 1
---
# A bot is one thing watched and one thing done
"Notify me when x.com is down." "Tell the todo guy when NYT has a new headline." That sentence is the
whole specification, and **the first message arms it** — a bot that interviews the owner first has already
failed at the thing that makes it a bot.
## Bot or commander — the line, and it is not size
- **A bot watches ONE thing and reacts.** A shell loop that exits when a condition is true. No ledger, no
procedures, no dispatch policy. Arming is `run_in_background: true` on a script and nothing else.
- **A commander runs a JOB.** It classifies, it decides, it spawns agents, it keeps `JOB.md` and a record
of what it has already handled, and it is set up in a conversation before it is armed.
If the answer to "what does it do when it fires" is one action, it is a bot. If the answer needs a
paragraph, or the thing has to remember what it already did, it is a commander. Reach for
[[commander]] there — and note that the bot brief tells bots explicitly NOT to read it, because a bot that
starts building a dispatch loop has stopped being a bot.
## Where everything is
```
$DATA_PATH/<owner-email>/bots/
├── CLAUDE.md the brief every bot runs under — PLATFORM-OWNED, rewritten every turn
├── <name>.sh the watch itself, one per bot
├── <name>.state its baseline, so a restart resumes instead of re-firing
└── <sessionId>.bot.json the record: script, state, pids, what it watches
```
Every bot shares that one directory — `getBotsDir(email)` — which is why the record is named for the
session id rather than filed under it.
The chat list for them is `GET /api/chat/sessions?context=bots`. The context IS the address: no `cwd`
needed, because there is only one bots directory per owner.
## `<sessionId>.bot.json` is the only thing that can stop a bot
A watch is a detached shell process. Nothing else on the machine knows it belongs to a bot — not the
transcript, not the session list, and not the process table, which sees an anonymous `bash`. The record is
the only link between the conversation and the pid.
That cost was paid before the file existed: a bot deleted on 2026-08-26 was still polling a website eleven
minutes later, with nothing in the product able to find it. So when a bot re-arms, it rewrites the record
with the new pid, in the same turn. A record that is stale is worse than absent — it names a pid that may
now belong to something else entirely.
## Why a bot has not fired — check in this order
1. **Is the process alive?** Read the record, then `ps -p <pid>`. A watch dies with a reboot and nothing
re-arms it automatically; the bot re-arms itself on its next turn, which needs a message.
2. **Has it fired already and not re-armed?** The exit IS the signal. A bot that fired, reported, and
never re-armed looks identical to one that is watching quietly.
3. **Is the baseline wrong?** A "has it changed" watch that wrote its state before exiting will not fire
on the same change twice. That is correct, and it is also the usual reason a test does not reproduce.
4. **Is it watching the wrong thing?** `watches` in the record is the bot's own description of its job.
Compare it to what the owner actually asked for before debugging any further down.
## The two ways a bot dies quietly
- **A reboot.** The loop is a plain background process; nothing supervises it. The record survives, which
is what lets the next turn re-arm from it — so a bot that has been silent since a restart is not broken,
it is unstarted.
- **A fired-and-forgotten watch.** It exited, said its line, and the turn ended without re-arming. Act,
re-arm, record — in one turn — is the rule in the brief precisely because forgetting the third step is
invisible until the thing never fires again.
## Setting one up for the owner
Say the sentence and let the bot arm itself. The brief in that directory is thorough and current — it is
rewritten on every turn from `src/servers/api/bots/brief.ts`, so it cannot drift from the platform the way
a copy here would.
**Do not paste the mechanism into the conversation.** If you find yourself explaining the script shape, the
record, or the naming rules to a bot, it has not read its own brief and the fix is to point at it.
## Naming
A bot's automatic title is the owner's first sentence, truncated, typos included. It is a prompt, not a
name. Two to four words, the subject and what is watched about it — `newweb uptime`, `NYT front page`,
`gitea disk space`. Not "Website Monitor Bot": every bot is a monitor, so the word earns nothing in a list
of them.
+1 -3
View File
@@ -42,7 +42,7 @@ diligence.
- API `/bug-report` - API `/bug-report`
- **Notifications** (`notify`) — Push notifications to your devices - **Notifications** (`notify`) — Push notifications to your devices
- API `/notify` - API `/notify`
- owner only, even when granted: `/broadcast` - owner only, even when granted: `/broadcast`, `/user`
- **Screen layouts and dashboards** (`dashboards`) — Where your own screen layouts and dashboards are saved - **Screen layouts and dashboards** (`dashboards`) — Where your own screen layouts and dashboards are saved
- API `/dashboards` · screen `/dashboards` - API `/dashboards` · screen `/dashboards`
- **Command HQ** (`command-hq`) — Long-running commanders you started, organised into categories - **Command HQ** (`command-hq`) — Long-running commanders you started, organised into categories
@@ -82,8 +82,6 @@ diligence.
- API `/app-store` · screen `/app-store` - API `/app-store` · screen `/app-store`
- **Plugins** (`plugins`) — Install, enable and remove the plugins this server runs - **Plugins** (`plugins`) — Install, enable and remove the plugins this server runs
- API `/plugins` · screen `/marketplace`, `/plugins` - API `/plugins` · screen `/marketplace`, `/plugins`
- **Todo board** (`todos`) — The platform's own backlog — todo/ in the repo, browsed and edited at /todos
- API `/todos` · screen `/todos`
- **Server settings** (`server-admin`) — Server configuration, integrations and the activity log - **Server settings** (`server-admin`) — Server configuration, integrations and the activity log
- API `/server-settings`, `/integrations`, `/activity`, `/system-monitor` · screen `/settings/server`, `/settings/system`, `/activity`, `/system-monitor` - API `/server-settings`, `/integrations`, `/activity`, `/system-monitor` · screen `/settings/server`, `/settings/system`, `/activity`, `/system-monitor`
- **User management** (`user-admin`) — Accounts, roles and what each role may reach - **User management** (`user-admin`) — Accounts, roles and what each role may reach