Skip to main content

colloquy

Presents a concept, design, decisions, findings, or a run of work in progress as an HTML page the user comments on in the browser — the agent watches for comments, replies in-thread, and ships revised versions as the work moves. Use instead of a wall-of-text plan or a handed-over .md report. Triggers: "explain this in HTML", "write it up as a page", "write up the findings", "I want to see the options", a run of work whose items the user will want to watch go by, or an intricate design that needs review.

Jump to install

Source facts

Repository
max-sixty/colloquy
Last source activity
August 8, 2026 at 23:13
Detected SKILL.md language
English
Stars
1
Forks
0

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
26 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
colloquy
description
Presents a concept, design, decisions, findings, or a run of work in progress as an HTML page the user comments on in the browser — the agent watches for comments, replies in-thread, and ships revised versions as the work moves. Use instead of a wall-of-text plan or a handed-over .md report. Triggers: "explain this in HTML", "write it up as a page", "write up the findings", "I want to see the options", a run of work whose items the user will want to watch go by, or an intricate design that needs review.
allowed-tools
["Bash(colloquy:*)"]
Present a concept, decision, findings, or work in progress as an HTML page the user opens in a browser and works in place — a colloquy: they select text and comment, decide and edit through what the page offers, you reply in-thread and ship revised versions, and a banner shows whether you're working or waiting on them. Reach for it instead of a wall-of-text plan or a `.md` report handed over by path, when a complex change needs shared understanding or a decision before code, when a diagnosis or review is itself the deliverable, or when a run of work has items the user will want to watch go by. With nothing named below, the subject is whatever the session is about — the plan you were about to give, the design under discussion, the findings you just gathered, or the work you are about to start. $ARGUMENTS ## Soul A page is the highest-bandwidth thing you can hand someone, so use it. Two habits carry most of that. **Shape follows the subject.** Ask what the subject *is* before writing about it. A set of things renders as things — `cq-milestones` for work with stages, `cq-board` for work the user re-orders, `cq-options` for a decision, `cq-metrics` for what was measured — and the prose says what only prose can. Five paragraphs about five items hand the reader the job of rebuilding the list you dissolved; the same five as items, each carrying its own state, are read at a glance and commented on one at a time. **A page that asks leaves somewhere to answer.** Anything you want a decision on ends in a `cq-options … choose`, wherever on the page the question falls. Give each alternative a `<strong>` title and its case — a sentence, or paragraphs with a `<dl class="facts">` rail — and the options stack as full-width cards, so an argued decision lives inside the group rather than in a table beside it. Where an alternative is a section of the page itself — a diagram, a diff, something no card should hold — let the group be bare labels naming those sections (`for="<section id>"`), which renders as a compact list; `multiple` where more than one can win. Every such group carries a box for words, so "none of these" and a pick's why need no separate gesture. A page presenting five candidates in prose and offering nothing to press has handed the reader a document where it meant to ask a question. **The page keeps up with the work.** A page is not only a thing to approve before the work starts. Where the work is yours to do and the page tracks it, publish a version each time the state moves — an item to `active`, then `done`; a finding added as you find it — and the user watches it happen instead of reading about it afterwards. Their browser follows each new version by itself, deferring only while they are mid-comment or mid-drag, so a version costs them nothing. Ship one when an item's state actually changes rather than at every step it took, and let `colloquy status <page> working "<detail>"` carry the finer grain in between. Keep `colloquy wait <page>` running while you work, in the host-specific loop below: a comment that lands mid-flight ("skip that one") then reaches you at the next step rather than at the end, and the banner reads as working throughout. Where other sessions do the work — workers reporting to a page one orchestrator publishes — they move it with `colloquy report <page> <widget> <verb> name=value…` instead of a version: a declared state change (a `cq-task`'s `status`, per the widget's x-report entry) that the page paints live as provisional news, marked as a report until a version answers it. It wakes the page's watcher like a user event, and the next version adjudicates it: write the reported state and publishing absorbs the report by id; keep your own state by marking the element `overruled` (why in the note); leave the markup unchanged and the report keeps painting. `version check` refuses a version that contradicts a standing report it never names — `page catalog`'s `$report` has the rest. ## Setup The page lives in its own directory, conventionally `~/.local/state/colloquy/pages/<slug>/`, where `<slug>` is a short kebab-case name for the topic (`migration-options`, `auth-diagnosis`) — every leaf command takes the page directory explicitly, so any location works. The directory survives the session and is where every version, the event log, and the vendored widget layer live. It is live state, not an archive: content with a life beyond the page leaves through `version export` or a copied version, to wherever that content belongs. The launcher is `${CLAUDE_SKILL_DIR}/../../bin/colloquy`. Resolve `${CLAUDE_SKILL_DIR}` to this skill's directory and use that launcher for every command shown as `colloquy` below. Claude Code also puts the same launcher on PATH. ```bash colloquy page init <page> # create layout, vendor the widget layer colloquy page catalog <page> # widgets and theme idioms colloquy page media <page> <file>… # add images; print each page path colloquy version check <page> --render # browser gate, once per page colloquy version publish <page> --version 1 --text "<changelog>" colloquy version export <page> -o <file> # standalone HTML copy colloquy server run <page> [--host NAME] # long-running; prints the URL colloquy status <page> working "<detail>" # or: waiting "<what you want back>", idle colloquy report <page> <widget> <verb> name=value… # a worker's state change, e.g. # report <page> t-parser status status=review colloquy wait <page> # prints unacknowledged user events and reports colloquy ack <page> <seq> # complete, untruncated output reached context colloquy comment <page> --quote "<passage>" --text "…" colloquy reply <page> --to <id> --text "…" colloquy events <page> # full event log colloquy transcript <page> # the exchange as Markdown ``` If the resolved launcher does not exist, the plugin payload is incomplete; say so. In a repository checkout it lives at `plugins/colloquy/bin/colloquy`. 1. Run `page init <page>`, then read `page catalog <page>`. It prints the vendored registry (widget schemas with examples) and the theme's class idioms, which vary per project. 2. Write the page as `<page>/versions/v1.html` (conventions below). 3. Start `server run <page>` as a long-running background command: a background task in Claude Code, or a unified-exec session in Codex. Hand over the URL it prints exactly as printed: the key in it is what opens the page. Address, key and port are all stable per directory, so the URL survives a restart. 4. Run `version publish <page> --version 1 --text "<changelog>"`. Publishing checks the version first and refuses a failure, so a half-written or broken file is never live in the user's browser. Before the URL first goes out, run the browser gate too: `version check <page> --render` (see "Before the URL goes out"). Then hand the user the URL with a one-line orientation (select text to comment; on a sign-off page, "✓ Looks good" approves; otherwise "End colloquy" ends comments without approval) and enter the loop. ## When the deliverable is the file `--export` in the argument asks for the file rather than the live page: steps 1, 2 and 4 as above, then `version export <page> -o <file>` and hand back the `file://` URL. No `server run`, no `colloquy wait`, no loop — the page directory is still built, so the same page can be served later without being rewritten, and the Stop hook covers only pages that were served or waited on, so it has nothing to say about this one. Write the file wherever the project puts things for the user to open. While a page is live the same command answers "give me a copy": `version export` writes any published version, as many times as asked, and the page carries on around it. The copy is the page as the browser drew it, with the user's decisions replayed onto it and the comment layer left behind. ## Page conventions - Pages are complete HTML documents. `version check` enforces the scaffold — exactly one stylesheet link (`/theme.css`) and one external script (the `/colloquy.js` module); the rest of the head (title, charset, the `cq-*` metas below) is yours: ```html <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>…</title> <link rel="stylesheet" href="/theme.css"> </head> <body> <main> …authored HTML and widgets… </main> <script type="module" src="/colloquy.js"></script> </body> </html> ``` - **The theme owns the look.** Palette, type, spacing, headings, tables, code, `details`, and the class idioms all come from the vendored `theme.css` — write plain semantic HTML and it gets the voice for free. A page-local `<style>` is the escape hatch for genuinely page-specific presentation, not for re-declaring the palette. - **Widgets are `cq-*` elements**, validated against the vendored registry: attributes carry scalars (enums, flags), children carry prose, an item's title is a leading `<strong>` child. Every `cq-*` element takes an explicit end tag — `<cq-diagram id="flow"/>` is rejected because HTML ignores the slash. A `data`-bodied widget (`cq-diagram`) holds its notation in a `<pre>`, with `<` and `>` escaped — the whitespace is load-bearing, and `<pre>` is the only thing in HTML that says so to a tool with no stylesheet to read. The catalog is the authority; don't invent tags or attributes. - Give every section, major block, and widget item a stable, meaningful `id`: comments anchor to the nearest `id`, and an anchor survives into a new version only where its id does. The reader's place on the page falls back to those same ids when the text around it was rewritten. Keep ids stable across versions so neither detaches, and out of the `cq-` prefix, which the runtime coins its own ARIA targets in. - **Edits to already-seen content ship as suggestions.** Changing a passage the reader has already seen — a rewrite, a deletion, above all the fix a comment asked for — goes in a `cq-suggestion`: `cq-old` carries the current markup verbatim (its ids ride there), `cq-new` the proposal, and the user accepts or rejects it in the margin. Fresh content — the first version, a new section, a restructure — is written straight, and comments cover it as usual. Name the answered thread with `resolves="<comment id>"` so accepting the fix closes the thread too. Deciding isn't the only answer: the proposed words are ordinary page text, so the user can select them and comment instead — worth saying where the page introduces its first suggestion, since ✓ and ✗ are the only visible affordances. - **Who writes the words picks the shape.** Three things change text once the page is in front of the user, and they differ by seat rather than by style. Prose you own, rewritten after the reader has seen it: a `cq-suggestion`, theirs to accept or reject. A passage that is theirs to word — a release note, a summary in their voice: a `cq-draft`, which nobody decides and the next version carries verbatim. Their wording for prose you own: a suggestion comment, which reaches the log for you to take or answer. So a draft never sits inside a suggestion — its words aren't yours to propose — and a suggestion carries markup, not a widget's own state: proposing a card's column or an option's pick has no form yet. - The runtime injects the status banner, comment sidebar, version picker, keyboard shortcuts (`?` in the browser shows the reference), and a left panel listing the machine's live colloquys with what each is doing or waiting for; don't build page UI for any of those. It also collects what the page is still waiting on the reader for — an undecided suggestion, a `choose` group with no pick, a task at `review` or `blocked` — into a banner count they can step through with `a`, from the vocabulary's own declarations (`x-awaits`). So write the asks as widgets and let the count find them; a hand-written "still open" list beside them is a second copy that goes stale the moment one is answered. - **Sign-off is declared, not assumed.** A page that asks for the user's assent — a plan, a design, a proposed change, anything where approval unblocks work — declares `<meta name="cq-review" content="sign-off">` in the head, and the banner offers "✓ Looks good". A page that only informs (a status report, an incident chronicle) omits it: it takes comments only, and the banner instead offers a neutral "End colloquy" control with no approval meaning. `version check` rejects unknown `cq-*` metas and any other `cq-review` value. - **Announce interactivity in prose.** Someone new to the page won't guess from a grip glyph or a hover cursor that a board takes drags or an options group takes clicks — the sentence introducing the widget says it ("drag cards to reprioritize; your edits reach me directly", "click an option to decide"). The widgets stay chrome-free on purpose; the page's own words carry the affordance. - **Never lose user text.** A central tenet of the comment layer: drafts (the general box, each reply, the selection composer) survive navigation, reload, version switches, and server death; only a successful send clears them. - **Diagrams are graphical, never ASCII.** Flow, sequence, and state diagrams go in a `cq-diagram` (mermaid source body); reach for hand-drawn inline `<svg>` only where layout must be bespoke, drawn from the theme's tokens, with labelled nodes and arrowheaded edges. Never box-drawing (`┌─┐ │ ▼`) in a `<pre>`. - **Name a code block's language and it gets colored.** Two shapes, by what the block is for: `<pre><code class="language-python">` for a literal the user selects and quotes — a command, a config, a snippet of output — and `<cq-code language="python">` for a walkthrough, which adds line numbers, `hi` ranges, and `cq-note` remarks anchored at a line. The language names are the same set either way, `page catalog` lists them, and `version check` refuses one outside it. Nothing is inferred from the text, so a block whose body isn't source — a transcript, a stack trace, a log — simply says nothing and stays plain. A `cq-diff` needs no language and takes none: a unified diff spans files, so each file's own path says what it holds, and a path naming nothing leaves that file plain like any undeclared block. - **Make references clickable.** Write source locations as ordinary semantic links, such as `<a href="https://host/repo/blob/main/path/to/file.py#L88"><code>path/to/file.py:88</code></a>`. Render ticket keys, MR/PR numbers, and URLs as real `<a>` links, not plain text. Inside a `<cq-specimen>` a fictional URL is fine. - **Keep wide content inside the column** — 720px in the default theme. The comment layer anchors to on-screen text, so a page that scrolls sideways is hard to comment on. Give any element that can overflow (a `<pre>`, a `<table>`, an `<svg>`) `max-width: 100%` or `overflow-x: auto`, and size diagrams responsively rather than a fixed pixel width wider than the column. `version check` flags fixed widths that exceed it. - **Images come in by reference, never inline.** `colloquy page media <page> <file>…` copies files into the page directory and prints the `src` to write; that path is the only form an image takes on a page, because a base64 `data:` URI is more bytes than you can usefully type and it would sit in every version forever. Each file is named by the hash of its bytes, so two versions showing one screenshot share one copy and a version the user approved cannot come to show them something else. `version check` refuses a `/media/` reference the directory can't answer. Where the deliverable is a change to a UI with a real *before* state, let the reader compare the renders rather than describing what moved: a `cq-shot` holds the pair and flips between them in place. Capture both states at the same viewport (the `/playwright-cli:playwright-cli` skill drives the browser; render the base commit in a second worktree rather than stashing). Say in prose what changed — a downscaled full-page shot shows that something moved and not what, and the column is 720px, so crop to the part that moved wherever the change is smaller than the page. - **Show real content as evidence; quote invented content in a specimen.** Prefer putting the actual file contents, diff, or output behind `<details>` over paraphrasing it. An example that merely exhibits syntax or a widget goes in a `<cq-specimen>` — its gutter and label mark the region as quoted rather than spoken, and interactive widgets inside take no input — with visibly fictional content: real project content in an example gets read as a live proposal. - **Show the destination, not the journey.** Explain the concept as it stands — total cut-over. Don't spend content on what was considered before or how you got here. ## Keeping the page current A page shows where its topic stands now, with what came before still on it. That is "Show the destination, not the journey" over time: the journey grows as the work does, so v1's destination — four options laid out for a decision — is the journey by v4, once the decision has been made and applied. Leaving it at full height in the order it was written turns the page into the record of the investigation, and the user has to work the present out of that. Each version is therefore a rewrite toward the present. The body carries what is live — the question in front of the user and what they need to answer it — and the lede says what the page is asking now. A section the topic has moved past goes to a `Settled` section at the foot: `<h2>Settled</h2>`, and under it one `<details>` per retirement, its `<summary>` naming the question and what closed it (the option picked, or the section that superseded it). Nothing is deleted. What retires moves intact, ids and all, so the anchors hold and `version check` passes, and a user who wants the argument behind a settled question opens it and finds what they read before. A `cq-options` group has the same move built in. `settled` collapses it to one line naming the pick, with every option behind a disclosure; the user can open it, disagree, and pick again. Reach for it where a decision retires inside a section that stays live; a section retiring whole takes its groups with it, marked the same way. Retiring is not revising. The words don't change, so it is neither a `cq-suggestion` nor grounds for `restated` — relocating a group the user picked in is a version agreeing with them. Time it by what is still moving rather than by what is finished. A decision stays live while you are applying it and settles once nothing is revisiting it, usually a version or two on, and a section the user is still commenting in stays in the body until that thread closes. ## The loop Whenever you hand over the URL or finish a round of work, run `colloquy status <page> waiting "<what you want back>"`, then enter the loop for the current host: Every handover message carries the page's URL again, so the user can open the page from the turn in front of them. - **Claude Code:** start `colloquy wait <page>` as a background task and end the turn. Its completion returns as host input: an idle session starts a turn, while a working session receives it between tool calls. Restart the background wait after each batch. - **Codex:** send the URL to the user in an intermediate update before waiting. Start `colloquy wait <page>` in unified exec, retain the returned session id, and keep the current turn active. Where the user owns the next move, poll that exact session with empty `write_stdin` calls and long yields until it returns. Where you are working, leave the same waiter running, continue the work, and poll it between tool calls or milestones so a comment can change the next decision. Never detach the wait and never end the turn expecting its completion to start another one: Codex has no unprompted completion delivery. Start a fresh wait session after each batch and retain its new id. While `colloquy wait` runs, the banner reads "<agent> awaits" and puts the `waiting` detail after it — the page's own line about what it needs from the reader. Write the thing you want back, in one short clause ("pick a storage engine", "check the two failure modes against what you saw"), rather than restating that you are waiting; the line shares a row with the page's controls and ellipsizes when they need the room. A page that asks nothing declares no detail, and the banner offers "select text to comment" instead. The same clause is what a reader sees against this page's name in every other colloquy's panel, which is where they pick which of several pages to come to — so name the ask, not the page's subject, which the title beside it already gives them. The wait can stay open as long as the user takes, and exits when they comment, reply, resolve, approve the page or end the colloquy, or edit an interactive widget (a drag on a `cq-board` arrives as an `action` event) — or when a worker session posts a `colloquy report`, which joins the same batch — printing the unacknowledged events as JSON lines. Printing is deliberately not receipt: a detached process can finish without its output ever entering model context. As soon as a complete wait result enters context, run `colloquy ack <page> <highest-seq>` before interpreting or handling it. If the wait output was truncated at all, acknowledge nothing: run a new wait with enough output capacity to receive the whole batch. A scalar cursor cannot represent a missing line in the middle. Acknowledgement is monotonic and idempotent; an event posted between wait and ack has a higher sequence and remains pending. Until ack, the next wait prints the batch again. Reading the full log with `colloquy events` does not acknowledge it. User comments exist only through the browser; `colloquy comment` posts as you, never as them. A wait result while the page already says `working` leaves that status untouched; `handoff` dates only a pickup from a non-working state. For each acknowledged batch: 1. Run `colloquy status <page> working "<what you're doing>"` and refresh the detail at each milestone. The banner shows it live, and reads a state left unrefreshed long enough as the agent having gone quiet. 2. Address every event `colloquy wait` printed. Each is JSON carrying the server-minted `id` that `colloquy reply --to` takes: - **A comment**: `colloquy reply` in-thread, and change the page where the comment warrants it — usually both. A reply's `--text` is brief Markdown — lists, `code`, fenced blocks, a table, bare URLs arrive as links — and every raw tag in it renders as its characters: write `<T>`, `<div>`, or a `cq-` tag in prose and the user reads exactly those words. Point at the page with an ordinary Markdown fragment link — "pick [the channel decision](#d-channel)" — and the words carry the reader to that element, opening whatever tab or settled group hides it. Reach for one whenever a reply names a part of the page: telling them where to look costs a sentence they then have to act on, where a reference is the act. Nothing checks the id, so keep it right; one this version hasn't got renders detached, like a quote whose passage left the page. To put a widget in the thread (a small `cq-diagram` explaining a fix renders live there), pass its markup as `--markup`, which renders after the text. `colloquy reply` validates it against the vendored registry and rejects what `version check` would, and a widget's ids must be fresh — it refuses ids the page or an earlier message already uses, and `version check` keeps later versions off a reply's. - **A suggestion** (a comment with `"suggestion": true`) proposes replacement text for its quoted passage: take it verbatim into the next version, or reply with why not — never silently rewrite it. - **A page-widget action** is the user editing the document through a widget — a board drag arrives as `{"kind": "action", "widget": "feeder-board", "action": "move", "detail": {"card": "card-baffle", "to": "col-doing", "index": 0}}`, an options pick with `"action": "choose"` and `"detail": {"options": ["st-s3"]}` (every option that now holds the pick, so an empty list is one cleared), a suggestion decided with `"action": "accept"` or `"reject"` — and they have already seen the change on screen. It stays on screen without your help: the page replays every recorded action onto every later version, so their edit survives a republish whether or not your markup mentions it. Write the next
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub