Compare commits
5
Commits
750ed9ecc2
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3f873fe4c2 | ||
|
|
79acaa5eb9 | ||
|
|
a57cb1b19d | ||
|
|
c24859c925 | ||
|
|
91596b7965 |
@@ -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,5 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: Commanders
|
name: commander
|
||||||
|
title: Commanders
|
||||||
description: >-
|
description: >-
|
||||||
Use when the user asks about a commander — what one is, how to start one, why one is not firing, how much
|
Use when the user asks about a commander — what one is, how to start one, why one is not firing, how much
|
||||||
one costs — or when they describe work that should keep happening while they are away ("watch X and do Y",
|
one costs — or when they describe work that should keep happening while they are away ("watch X and do Y",
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: Delegating the writing
|
name: delegating
|
||||||
|
title: Delegating the writing
|
||||||
description: >-
|
description: >-
|
||||||
Use when a feature has been agreed and somebody has to type it — how to hand the writing to a cheaper
|
Use when a feature has been agreed and somebody has to type it — how to hand the writing to a cheaper
|
||||||
agent, what a brief has to contain, and how to review what comes back. Also read it before deciding NOT
|
agent, what a brief has to contain, and how to review what comes back. Also read it before deciding NOT
|
||||||
|
|||||||
+34
-1
@@ -1,5 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: Deploying Officer
|
name: deploy
|
||||||
|
title: Deploying Officer
|
||||||
description: >-
|
description: >-
|
||||||
Use when asked to deploy, release or roll out Officer, to watch for a release and deploy it, or when a
|
Use when asked to deploy, release or roll out Officer, to watch for a release and deploy it, or when a
|
||||||
deploy has gone wrong — a host behind, a tag not noticed, a rollout that stopped halfway. Points at the
|
deploy has gone wrong — a host behind, a tag not noticed, a rollout that stopped halfway. Points at the
|
||||||
@@ -66,6 +67,38 @@ money. That is not hypothetical.
|
|||||||
- **A dirty tree means TRACKED changes.** `git status --porcelain` counts untracked files; a stray script a
|
- **A dirty tree means TRACKED changes.** `git status --porcelain` counts untracked files; a stray script a
|
||||||
fast-forward could never touch is not a reason to skip a host. Use `--untracked-files=no`.
|
fast-forward could never touch is not a reason to skip a host. Use `--untracked-files=no`.
|
||||||
|
|
||||||
|
# `db:push` can offer data loss at a prompt, and it waits for an answer
|
||||||
|
|
||||||
|
A schema push on a host that is many commits behind can stop and ask whether a table was RENAMED. Both
|
||||||
|
answers destroy something, so neither is safe to guess and neither is safe to automate.
|
||||||
|
|
||||||
|
Seen 2026-08-27 catching `edge-pertento-bridge` up by 215 commits:
|
||||||
|
|
||||||
|
```
|
||||||
|
Is command_hq_spawned table created or renamed from another table?
|
||||||
|
❯ + command_hq_spawned create table
|
||||||
|
~ dav_app_passwords › command_hq_spawned rename table
|
||||||
|
```
|
||||||
|
|
||||||
|
drizzle-kit saw one table leaving the platform schema and another arriving, and could not tell a rename
|
||||||
|
from a coincidence. `rename` would have turned the DAV app passwords into the spawned-commander table;
|
||||||
|
`create` would have dropped them.
|
||||||
|
|
||||||
|
**The table had not gone anywhere — it had moved to a PLUGIN.** Caldav was extracted that day, so
|
||||||
|
`dav_app_passwords` belongs to `plugins/caldav/db/schema.ts` and reaches the barrel through
|
||||||
|
`gen-plugin-schemas`. Installing the plugin FIRST declares it, and the question disappears.
|
||||||
|
|
||||||
|
So, on a host far enough behind that a plugin extraction is in the gap:
|
||||||
|
|
||||||
|
1. Install the plugins whose tables are involved, **before** pushing.
|
||||||
|
2. Then `bun db:push < /dev/null` — stdin closed, so it can never hang waiting on a prompt in an
|
||||||
|
unattended run. A push that needs an answer fails instead, which is the outcome you want.
|
||||||
|
3. Expect ONE failure on a `role_permissions` foreign key, then `seed-roles.ts`, then push again. That
|
||||||
|
sequence is normal on a host predating the roles table.
|
||||||
|
|
||||||
|
**Back up the database first.** `pg_dump` against the URL in `.env` — and read the variable name rather
|
||||||
|
than assuming: several hosts use `OFFICERDEV_POSTGRES_URL`, not `POSTGRES_URL`.
|
||||||
|
|
||||||
# The report is an artefact, the lock is the record
|
# The report is an artefact, the lock is the record
|
||||||
|
|
||||||
Write the local record FIRST, then commit and push the report. If the push fails, say so and stop: the
|
Write the local record FIRST, then commit and push the report. If the push fails, say so and stop: the
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: Officer platform
|
name: platform
|
||||||
|
title: Officer platform
|
||||||
description: >-
|
description: >-
|
||||||
Use when the user asks what Officer can do, how to use a feature, what an endpoint is, why something is
|
Use when the user asks what Officer can do, how to use a feature, what an endpoint is, why something is
|
||||||
refused, or how permissions and accounts work — "how do I start a commander", "can a member see my files",
|
refused, or how permissions and accounts work — "how do I start a commander", "can a member see my files",
|
||||||
@@ -41,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
|
||||||
@@ -51,8 +52,6 @@ diligence.
|
|||||||
|
|
||||||
- **Memos** (`memos`) — Notes
|
- **Memos** (`memos`) — Notes
|
||||||
- screen `/memos`
|
- screen `/memos`
|
||||||
- **Calendar and contacts** (`calendar`) — Calendars, contacts, and the app passwords that sync them to a phone
|
|
||||||
- API `/caldav`, `/dav` · screen `/calendar`, `/contacts`
|
|
||||||
- **SendOff** (`sendoff`) — Send files to your own machines, and to accounts that have allowed you
|
- **SendOff** (`sendoff`) — Send files to your own machines, and to accounts that have allowed you
|
||||||
- API `/sendoff` · screen `/sendoff`
|
- API `/sendoff` · screen `/sendoff`
|
||||||
|
|
||||||
@@ -83,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
|
||||||
|
|||||||
Reference in New Issue
Block a user