Compare commits

...
2 Commits
Author SHA1 Message Date
pastilhasandClaude Opus 5 8a1bcb03f5 a new app starts from the template, and its dev server runs in the background
two things an agent cannot discover and gets wrong by default.

FIRST: asked to create an app, it scaffolds one. there is a template —
templates/template-react on gitea — and it is the agreed starting point. it
documents itself, so this points at its README, CLAUDE.md and CONVENTIONS.md
rather than restating them; the one thing worth lifting out is README step 1,
the rename, because it costs thirty seconds at the start and is a chore
forever after.

SSH not HTTPS, verified both ways: the https remote prompts for a username and
dies in a non-interactive shell. the tailnet address is noted as the fallback
for when the public host's ssh is being rate-limited, which the deploy skill
already records as a recurring thing.

SECOND: asked to run it, it runs bun dev in the foreground, which blocks until
the tool times out and reports a working server as a failure. backgrounding is
both the only thing that works AND what the owner wants — a background job gets
officer's live panel, the same one they would see running it themselves, so
they can read the output and stop it without asking.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Officer-Session: 656f5c85-e49a-4f1f-b9f3-042a04b4d043
2026-08-25 20:10:44 +00:00
pastilhasandClaude Opus 5 d963bd0a4c the one process an agent must never restart is its own
pm2 restart officer-claude-code tree-kills the sidecar, which takes claude and
the agent's shell with it. the tool call never returns, the conversation stops
dead, and the harness records it as an INTERRUPTED or REJECTED call — so the
transcript blames the user for something they did not do. that misattribution
is the expensive part: it sends everyone looking in the wrong place. the owner
had seen it before and could not reproduce it.

pm2 restart officer is safe and always was — sidecars are peers of the main
server, not its children. only the agent's own host is special.

and the trap underneath it, which is quieter: a change under
src/servers/sidecar/claude/ does not take effect when officer restarts,
because it lives in the process the agent is running inside. on 2026-08-25 a
credential scope was widened, officer was restarted four times, and the sidecar
carried the previous build all day while every report said otherwise. check the
process uptime before claiming a change is live.

the way out is to ask the owner, or to detach with setsid and say first that
the session is about to end.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Officer-Session: 656f5c85-e49a-4f1f-b9f3-042a04b4d043
2026-08-25 18:45:02 +00:00
2 changed files with 123 additions and 0 deletions
@@ -0,0 +1,67 @@
---
name: Restarting your own host
description: Use before restarting, stopping or reloading any PM2 process, and whenever a change you made lives in a sidecar rather than in the main server. Names the one process that kills you, and what to do instead.
version: 1
---
**You are a child of `officer-claude-code`.** Your process tree is:
```
zsh ← every Bash command you run
claude --output-format stream-json …
bun run src/servers/sidecar/claude/user-instance.ts ← officer-claude-code, a PM2 process
PM2 God Daemon
```
So **`pm2 restart officer-claude-code` kills you, mid-command.** PM2 tree-kills the sidecar, which takes
`claude` and your shell with it. The tool call never returns. What the user sees is the conversation
stopping dead — and what the harness records is an *interrupted* or *rejected* tool call, so the transcript
blames them for something they did not do. That misattribution is the worst part: it sends everyone
looking in the wrong place.
The same applies to `pm2 stop`, `pm2 delete`, `pm2 reload` and `pm2 restart all` or
`ecosystem.config.cjs`, which include you.
## What is safe
**`pm2 restart officer` is safe.** The sidecars are PM2 PEERS of the main server, not its children, so
restarting `officer` costs you a socket reconnect and nothing else. Every other sidecar —
`officer-pty`, `officer-email`, `officer-notify` and the rest — is equally safe for the same reason.
Only your own host is special.
## The trap this actually sets
A change under `src/servers/sidecar/claude/` — the session credential, the manager, the transcript
reader — **does not take effect when you restart `officer`.** It lives in the process you are running
inside. So the honest failure mode is not a crash, it is this:
> You edit the file, restart `officer`, report the change as live, and it is not. The old code keeps
> running for hours while everything you say about it is wrong.
That happened on 2026-08-25: a credential scope was widened, `officer` was restarted four times, and the
sidecar carried the previous build all day. The symptom was a legitimate refusal that read as a bug.
**So check which process owns your change before you claim it is live.** `pm2 jlist` gives each process's
uptime; if the sidecar's start time predates your edit, your edit is not running.
## What to do instead
**Ask the user to run it.** One line, and they are already there:
```
pm2 restart officer-claude-code
```
Say why it is theirs to run rather than yours — that it ends this session — so it does not read as
helplessness.
If it genuinely must happen without them, detaching it from your process group is the only form that
survives, and **it still ends this conversation** — the restart completes, you do not:
```
setsid nohup sh -c 'sleep 2; pm2 restart officer-claude-code' >/dev/null 2>&1 &
```
Never do that silently. Tell the user first that the session is about to end, or they will see exactly
what this affordance exists to explain.
@@ -0,0 +1,56 @@
---
name: Starting an app
description: Use when asked to create, scaffold or start a new app or project, and when asked to run one. There is a template to begin from, and a specific way the owner expects a dev server to be started.
version: 1
---
**Do not scaffold a new app from scratch.** There is a template, it is the agreed starting point, and it
carries decisions that took a while to settle.
```bash
git clone git@gitea.officer.dev:templates/template-react.git <name>
```
Bun · Hono · React 19 · Tailwind v4 · shadcn/ui · Postgres with Drizzle. A JSON API at `/api` and a React
app at `/`, over one query layer.
**SSH, not HTTPS.** `https://gitea.officer.dev/…` prompts for a username and fails in a non-interactive
shell; the SSH remote is already authenticated. If SSH is being refused for a stretch — the public host is
behind a proxy that rate-limits it — `ssh://git@100.64.0.13:10023/templates/template-react.git` is the same
repository over the tailnet.
## Then read its own documentation, and do step 1
The template documents itself. **`README.md` step 1 is a rename** — everything project-specific is called
`app`, and a case-sensitive search for `app`, `App` and `APP` finds all of it. Thirty seconds at the start,
a chore forever after. Do it before the first commit.
Its `CLAUDE.md` points at `CONVENTIONS.md` (React patterns, feature folders, manager hooks),
`docs/DATABASE.md` and `docs/SURFACES.md`. Read those rather than inferring house style from the code —
they exist so the same argument is not had twice.
Drop the template's git history and start your own unless told otherwise: it is a starting point, not an
upstream to track.
## Running it — always as a background job
```bash
bun dev
```
**Start it in the BACKGROUND, never in the foreground.** Two reasons, and either one is sufficient:
- **A dev server does not exit.** Run in the foreground it blocks the turn until the tool times out, and
the timeout is reported as a failure of a thing that was working perfectly.
- **The owner wants to watch it.** A background job gets Officer's live panel — the same one they would
see running it themselves — so they can read the output, see the port, and stop it. Run any other way it
is invisible, and stopping it means asking you.
`bun dev` prints steadily, so the panel fills immediately. `predev` regenerates the index first; that is
normal and takes a moment.
The general rule about background output still applies — see the background-jobs affordance. It matters
less here only because this particular command is already talkative.
**Say the URL when it comes up.** The port is in `.env` and the template's README, and the first thing
anybody wants after "it's running" is where to look.