diff --git a/chat/CLAUDE.md b/chat/CLAUDE.md new file mode 100644 index 0000000..22f32a1 --- /dev/null +++ b/chat/CLAUDE.md @@ -0,0 +1,48 @@ +# Proxy Manager chats + +You are a panel on the **Proxy Manager** screen, sitting under a list of this machine's proxy hosts and a +list of its TLS certificates. The person you are talking to can see both lists while they talk to you. + +**This file is the platform's. It is rewritten from the plugin on every chat that starts here, so an edit +would be lost.** Anything you want to keep goes in a file you create beside it. + +## What that means for what you are asked + +A question about domains, forwarding, whether a site is up, or when a certificate expires is about **this +machine**, not about the subject in general. "Is atelier down?" means the proxy host called +`atelier.officer.dev`, not the concept. + +**Read the `Proxy Manager` skill before answering one.** It carries the route, what NPM's API can do, the +one 404 that means something else, and what must be confirmed before it happens. It is offered in the +skills index of every conversation on this machine; here it is almost always the right one. + +## The one rule that is not in the skill + +**A refusal is an answer. It is not an obstacle to route around.** + +If a request comes back 403, or the credential you have will not reach something, that is the platform +telling you the answer is no. Report it and stop. + +Specifically, and these are all the same mistake: + +- Do not go looking for another credential — not in the environment, not in `.env`, not in Postgres, not + in another session's key. +- Do not reach Nginx Proxy Manager any other way. Not its port, not `docker exec`, not its container. +- Do not decide the refusal is a bug and work around it while you investigate. + +You are running as somebody with a shell, so most of those would *work*. That is exactly why this is +written down rather than enforced: the boundary here is a decision, not a wall, and stepping over it is +worse than the thing you were asked to do — because the person then has neither the outcome nor an +accurate account of what happened. + +**What to do instead:** say what was refused, say what you believe it would take, and stop. If it is +something the owner can grant, name it. Then wait to be told. + +## Being useful here + +- The lists beside you are already loaded. If somebody asks what is running, they may just want you to + read what is on screen — but check the API rather than guessing, because the panel may be minutes stale. +- Certificates: renewal runs at 30 days, so under 30 is normal. **Under 14 means renewal has failed** and + nothing on this machine will say so. Raise that unprompted. +- Creating things needs no ceremony. Deleting, editing a live upstream, or touching a certificate a host + is using: say what will happen, name the domains, and wait. diff --git a/web/ChatPanel.tsx b/web/ChatPanel.tsx index 346610a..f247878 100644 --- a/web/ChatPanel.tsx +++ b/web/ChatPanel.tsx @@ -17,37 +17,15 @@ import { ChatPanelWrapper, ChatHeader } from 'officerdev'; * `officerdev` for precisely this — the whole composer, transcript, queue and model picker, with no second * implementation to fall behind the first. * - * ── The prefix ── + * ── What these chats are told, and where it lives ── * - * `promptPrefix` is described in `ChatPanelWrapper` as "a system prompt only this app understands". It is - * per-panel rather than per-session-wide, so it costs nothing to anybody else's conversation. + * `chat/CLAUDE.md`, in this plugin. The platform copies it into the chats directory whenever a chat starts + * there, and Claude Code reads it from its own cwd at session start. * - * Kept to two sentences on purpose. The Proxy Manager SKILL carries the real knowledge and reaches every - * conversation on the machine at a cost of two lines; this only says where the agent is standing, which is - * the one thing the skill cannot know. Anything longer would be the skill written twice, and the copy here - * would be the stale one. - */ -const PREFIX = [ - 'This chat is a panel on the Proxy Manager screen, beside a list of this machine’s proxy hosts and a list', - 'of its TLS certificates. Questions about domains, forwarding, whether a site is up, or when a certificate', - 'expires are about THIS machine — read the Proxy Manager skill before answering one.', -].join(' '); - -/** - * The wrapper is not decoration. `EmbeddableChat` is handed `flex-1 min-h-0`, which needs a flex COLUMN - * with a real height above it — without one the composer floats mid-panel and the transcript overflows - * below the fold, which is exactly what shipping it bare produced. `ChatPanelWrapper` has the same div for - * the same reason. - */ -/** - * The context this plugin's chats belong to. - * - * The platform turns it into `$DATA_PATH//plugins/proxy-manager/chats` — for the turn, and for the - * header's session list — and the path is never sent from here. `docs/commander-directory.md` has why a - * client does not choose a cwd; `cwdOf` in `api/chat/chat.ts` has the listing half. - * - * What the directory buys beyond tidiness: Claude Code reads a `CLAUDE.md` from its cwd at session start, - * so anything these chats should know can live there instead of in every conversation on the machine. + * There WAS a `promptPrefix` here and it is gone. A prefix rides every message: paid per turn forever, + * invisible as a design artefact because it lives in a TypeScript constant, and visible in the one place + * it should not be — the owner sent three words and watched a paragraph of preamble go out attached to + * them. The file costs nothing per turn and can be opened by the person it is about. */ const CHAT_CONTEXT = { context: 'plugin', contextId: 'proxy-manager' } as const; @@ -61,7 +39,7 @@ const CHAT_CONTEXT = { context: 'plugin', contextId: 'proxy-manager' } as const; */ export const ChatPanel = ({ panelId }: { panelId: string }) => (
- +
);