share-as-page
Skill4 starsChanged 56 days agoMITView on GitHub
Turn ANY document, report, research finding, analysis, audit, runbook, checklist, plan, meeting recap, or conversation summary into a polished, on-brand, self-contained HTML page, OPEN IT IN THE KNOWLEDGE BASE (hq-open), and optionally host it on a shareable URL. Resolves brand tokens (color, fonts, logo) so the page looks like it belongs to the ASSOCIATED brand. This is the DEFAULT path for any visual/document deliverable for this user — there is NO side panel here, so NEVER use SendUserFile and never dump long content to the terminal; build the page and open it in the Knowledge Base with `hq-open <path>` (never `open` on the file; ruled 12 Sep 2026). Use whenever producing a runbook / doc / one-pager / checklist / report / plan / page for the user to read, or when the user says "show me", "display this", "turn this into a page", "make it an HTML <anything>", "make it shareable / host this / send a link", or hands over finished content to look at or share.
In this repository5 other files it gives its agents.
- tb-voice/AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- tb-voice/CLAUDE.mdCLAUDE.md
- hubSkill
- research-hqSkill
The file
We split this skill into the rules it gives an agent
11 rules. About 0 are common, 8 are distinctive, and 3 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈8
Distinctive · estimate
This author's own choices. Worth a look.
3
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 31
Create the dir; a report.md may already be there if this is a research brief.
- Distinctive: line 38
When unsure, it's a document.
- Distinctive: line 48
Don't re-research; this skill packages content that already exists in the conversation or a file.
- Distinctive: line 60
If two readings are plausible (a Kopi analysis *of* a customer — Kopi's brand or theirs?), ask.
- Distinctive: line 63
If no brand genuinely applies, say "unbranded — using the editorial default." That is a legitimate outcome (and a good-looking one — see …
- Distinctive: line 160
Do not write the agent footer yourself: Every page written under your agent directory gets it stamped by the app's hook after the write …
- Very specific: line 183
Keep the readable defaults (66ch measure, 18px/1.65, the @media print block).
- Distinctive: line 192
Never ship a page you haven't looked at.
- Distinctive: line 219
If a check fails, fix the tokens — not the layout.
- Very specific: line 263
Tokens, not hard-codes: All brand color/font decisions live in :root custom properties so a re-brand is a few-line edit.
- Distinctive: line 271
Lightweight: No JSON data model, no logo pipeline, no build step beyond the deploy.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
share-as-page
Turn content you already have (a report, research, audit, recap) into one self-contained, on-brand HTML file and deploy it to a shareable URL. One template → brand tokens → inline everything → one deploy command.
Skill dir (<skill dir> below): the directory holding this SKILL.md; Tranquility Base links it into every harness — templates/report.html, references/layout.md,
scripts/deploy.sh.
Where the page lands — decide first, it's binary:
- A document for the user (research brief, report, runbook, audit, plan, recap — anything
they read or archive): land it in HQ —
<hq_root>/YYYY-MM-DD-<slug>/index.html, wherehq_rootdefaults to~/Documents/deep-research(see the research-hq skill's config). Create the dir; areport.mdmay already be there if this is a research brief. Hosting for HQ pages goes through the central publisher (hq-publish --deploy, gated on theintranet:visibilitymeta tag) — NOT the per-dir deploy below. - Client-facing standalone deliverable (a page someone external receives as its own URL,
wearing their brand): work in
~/Projects/<slug>-page/— the-pagesuffix is REQUIRED, the dir name becomes the URL — and deploy withscripts/deploy.sh.
When unsure, it's a document; HQ is the default.
This is the default reusable path. If the content has a strong native metaphor (e.g. a boarding pass for a travel brand) you may design a bespoke layout instead — but still follow the same token + inline + deploy rules below.
Workflow
1. Gather the content
Identify exactly what to render — the report/analysis/recap text, its sections, any tables. Don't re-research; this skill packages content that already exists in the conversation or a file. Pick a short kebab-case slug for the project dir and the URL.
2. Name the brand — an explicit decision, out loud
Every page belongs to exactly one brand, and you must say which before you author anything.
Not "implied." State it: "Styling this as <Brand> (<brand id or domain>)."
- The brand is usually whoever the document is about or for — the client in a client report, the user's own company for internal docs.
- Internal Kopi documents → the Kopi brand. See
references/brands.md, which records Kopi's own tokens so you never have to reconstruct them. - If two readings are plausible (a Kopi analysis of a customer — Kopi's brand or theirs?), ask. It's one line and it prevents the whole page being wrong.
If no brand genuinely applies, say "unbranded — using the editorial default." That is a legitimate outcome (and a good-looking one — see rung 5). Silently drifting into it is not.
2a. Resolve the tokens — and record where each one came from
You need: --color-brand, --color-accent, --color-text, --color-bg, --color-heading,
--font-heading, --font-body, and a logo (data URI).
Work down this ladder and stop at the first rung that yields a value:
- Explicit — the user gave colors/logo/fonts in conversation.
- Recorded —
references/brands.mdhas this brand. - Kopi brand record —
set_active_brand(query by name) →get_context. Map the briefing:colors.primary→--color-brand;colors.primaryForeground→ on-brand foregroundcolors.bodyBackground→--color-bg;colors.textBody→--color-textcolors.textHeading(or--color-brandif null) →--color-headingfonts.heading.family/fonts.body.family→ font tokens- Logo: the brand's logo if present; else rung 4 for the logo only.
Take
--color-accentfrom the brand's secondary colour, or sample the logo.
- Site scrape —
WebFetch/curl the brand site:meta[name=theme-color]→ brand colour;og:image/apple-touch-icon/ a.logoimg → logo. Base64-embed it (see references/layout.md). - Editorial default — the house style already in
templates/report.html: Newsreader (serif, embedded) + Libre Franklin (labels, embedded), near-black ink on warm paper white, hairline rules, kicker/dek/byline masthead. It is a deliberate, publication-grade unbranded look — NYT/FT-class newspaper typography, recognisably a well-set independent document, never a guessed-at brand. Falling back here is a fine outcome, not a failure; say "unbranded — editorial default" and ship it. (Old grey-band template preserved attemplates/report-v1-corporate.htmlif a page needs the previous look.)
The provenance block is mandatory. The template's :root opens with a PROVENANCE comment.
Fill in every token with the rung it came from, then state the same summary to the user in chat:
/* PROVENANCE — brand: Kopi (V8UOFCQfdeUrGvYDp_gPE)
--color-brand #1E3A52 rung 2, references/brands.md
--color-accent #FF6B4A rung 2, references/brands.md
--font-heading Bricolage Grotesque rung 2, embedded @font-face below
logo rung 4, scraped trykopi.ai/apple-touch-icon.png */A token with no rung is a bug, not a style choice.
NEVER INVENT A TOKEN
Do not pick a hex because it feels right for the brand. Do not nudge the template defaults "toward" a vibe. Do not derive a palette from a company's name, industry, or product metaphor. Do not treat an app's own UI theme as its brand — a product's
globals.css/ Tailwind config is usually shadcn-style neutrals, deliberately colourless so customer brand colours can sit inside it. That is chrome, not identity. Sampling a favicon gives you one or two real colours; it does not give you a background, a text colour, or a rule colour.When the ladder runs out, take rung 5 and tell the user which tokens are unresolved. A page honestly marked "unbranded — editorial default" is fine; the house style exists so the fallback is handsome without pretending to be anyone's brand. A page that looks branded but isn't is worse than a plain one, because the
:rootblock implies a provenance it doesn't have — and the user has no way to see the difference. (The editorial default's own accent red and paper tones are house-style constants, not brand claims — leave them as-is or override with rung-sourced values only.)
Fonts must actually load. Naming a family in a stack does nothing on a machine that lacks it.
Either embed it as a data-URI @font-face (scripts/embed-font.sh) or use a system stack and say
so. A named-but-unembedded font is a silent failure — the page renders in a fallback and looks fine.
Foreground rule (accessible, one line): for any colored background, compute relative luminance L; if L > 0.179 use black text, else white (guarantees ≥4.5:1). Logos are exempt.
2b. Lead with what needs the reader — mandatory ordering
If the page contains anything the reader must decide, approve, or answer, that block goes directly after the dek — above the findings, not at the end. One line per decision, the options, and your recommendation. Everything below it is support.
Ruled 18 Aug 2026 after a report buried two "your call" blocks under 2,000 words of evidence: "hierarchy means needs-you is at the top, not the bottom." Writing the page in the order you did the work is the failure mode — the reader is there to act, not to follow the investigation. If nothing needs them, say that at the top too.
3. Author the HTML
A report Robert reads to act starts from templates/brief.html, and references/brief.md
says how to fill it: one sentence they cannot miss, one row per claim, the artifact (screenshot,
diff hunk, raw rows, literal prompt) collapsed under each claim. Ruled 25 Sep 2026 after 974
hub pages were measured: median 908 words, 17% with any visual, and the decision box the only
rule the old template enforced. templates/report.html (the editorial serif page) remains for a
document meant to be read through, and for anything leaving the building.
Copy the template to <project>/index.html, then:
- Declare the intranet metadata in
<head>— mandatory on every page, same footing as the PROVENANCE block. The intranet index parses these deterministically; a page without them gets keyword-guessed metadata, which is how work goes missing:<meta name="intranet:brand" content="<the brand named in step 2>"> <meta name="intranet:type" content="<research|page|runbook|plan|audit — what it IS>"> <meta name="intranet:question" content="<one line: what this page answers or decides>"> <meta name="intranet:status" content="<draft|final|shipped>"> <meta name="intranet:visibility" content="<local|hosted>"> - Do not write the agent footer yourself. Every page written under your agent directory gets it stamped by the app's hook after the write (session id, Open hub, Discuss with agent), with the owner read from the directory, which is your FULL session id. A hand-written footer is what produces two, and the old hand-written one pointed at a short 8-character folder that nothing uploads (30 Sep 2026: fourteen reports stranded that way). A page kept outside the agents tree gets no footer; link it from a page inside the tree instead.
- Set the
:roottokens to the resolved brand values. - Replace the
<title>, nameplate (<!-- BRAND NAME -->, optional<!-- LOGO -->), the<!-- KICKER -->(section label, e.g. "Research Brief"),<!-- TITLE -->,<!-- DEK -->(one-sentence standfirst),<!-- BYLINE -->, and the editorial<footer>line — it names the page's own subject and date, so an inherited one is a lie about what you just wrote. - If you seeded this page by copying a previous page rather than the exemplar, every item in the list above is someone else's until you replace it. The footer is the one that survives, because it sits below the content you rewrote and reads as furniture: 40 pages in this HQ carried "Stop operating the newsletter workflow · August 11, 2026" across nine days and a dozen unrelated subjects, each copied from the last. Check the bottom of the page before you call it done.
- Replace
<!-- CONTENT -->with the report as semantic HTML (<section>,<h2>,<p>,<table>,<ul>). Keep prose to the--measurewidth; tables/chips may go full width. Editorial devices available:<p class="dropcap">opening graf, pull-quote<blockquote>with<cite>, top-rule stat.chips,<span class="endmark">on the final paragraph. - Inline everything — no external requests. CSS stays in
<style>; embed the logo and any non-system fonts as data URIs. The template ships with Newsreader + Libre Franklin already embedded; keep them for unbranded pages, replace/remove them when a brand's fonts take over. - Keep the readable defaults (66ch measure, 18px/1.65, the
@media printblock). Seereferences/layout.mdfor the cheat sheet and snippets.
Raise the page to the brand using the tokens you resolved — an accent band, a logo lockup, on-brand section styling. Craft lives in how you deploy the resolved values (weight, spacing, proportion, where the accent lands), never in inventing new ones. If the page feels generic and the tokens are all rung 5, the honest fix is to resolve a brand — not to add colour by feel.
4. Visual eval — REQUIRED, before any deploy
Never ship a page you haven't looked at. Render it and inspect the actual pixels:
bash <skill dir>/scripts/shot.sh <project-dir> /tmp/preview.pngThen Read /tmp/preview.png and check, concretely:
- Centering & width — masthead, chips, prose, and tables share one aligned column; no content pinned left with a dead right gutter; no horizontal overflow.
- Contrast — text readable on any brand-colored surface (the
--on-brandchoice was right). - Serif actually rendered — headline and body must show Newsreader (or the brand face), not
a fallback sans; if headings render sans, the
@font-faceblocks were stripped or renamed. - Spacing & overflow — nothing clipped, no text overlapping, tables not blown out.
Then run the brand-fidelity check, which is a different question from "does it look good." A page with an invented palette looks perfectly good — that is exactly why this check exists and why the rendering checks above cannot catch the failure:
- Provenance first — re-read your
PROVENANCEblock. Every token has a rung? Any token you cannot name a source for is invented; go back to step 2a and resolve or fall back to neutral. - Against ground truth, not vibes — put the screenshot next to the brand's actual logo, site, or recorded tokens. Would someone who knows this brand recognise the page as theirs? "Coherent and attractive" is not the bar; "unmistakably this brand" is.
- Font actually rendered — compare the heading glyphs to the font you claimed. If you
declared a distinctive family and the screenshot shows plain system sans, the
@font-faceis missing and the token is a lie. This is invisible in every other check. - Logo is the real mark — it renders, and it is the brand's actual logo, not a favicon frame, a placeholder, or a coloured shape you drew.
If a check fails, fix the tokens — not the layout. Re-shoot. Only then deploy.
Fix the HTML and re-shoot until it's right. Only then deploy. (Optionally shoot a narrow
width too, e.g. ... /tmp/m.png 420 900, to catch mobile breakage.) This gate is not optional —
the most common failures (off-center columns, missing logo, low contrast) are invisible until rendered.
5. Deploy
bash <skill dir>/scripts/deploy.sh <project-dir>Prints the live *.vercel.app URL. (Primary = Vercel, proven non-interactive. Fallbacks below.)
6. Hand off
Give the user the URL and offer one revision pass. Mention they can ⌘P → Save as PDF (the print CSS is wired). If any benchmark/number came from the conversation, don't invent new ones.
Hosting reference
- Vercel (default):
deploy.shrunsvercel deploy --prod --yes; readsVERCEL_TOKENfrom env if set, else ambient login. Persistent clean alias. - surge.sh (fallback, pick-your-subdomain):
surge ./dir my-slug.surge.shwithSURGE_TOKEN+SURGE_LOGIN. Unlimited, persists untilsurge teardown. - Netlify anonymous (zero-auth one-shot):
netlify deploy --dir=./dir --allow-anonymous— but the claim window is ~1h with undocumented persistence; use only for throwaway links. - Skip GitHub Pages for agent use — needs repo + branch + Actions, too multi-step.
Rules
- One self-contained file. It must render double-clicked offline and over the web with zero external requests. Inline CSS and fonts (data URIs) — always, no exception. Type is the difference between a page that looks right offline and one that does not.
- Images may live in the bucket, and only there. Measured 07 Sep 2026: 72 of 1756 archive
pages hold inline images and those 72 carry 94.6 MB — 35% of all the HTML on disk, four pages
alone accounting for 75 MB. So raster media is the one class worth an outside dependency.
It is allowed from
assets.base_urlinhq.jsonand from nowhere else: a.pngon somebody else's CDN is still a page that stops working when they reorganise, andcheck-brand.shstill fails it. Whileassets.base_urlis unset the old rule stands unchanged and everything must be inline. Useresearch-hq/scripts/extract-media.pyto move existing pages; it verifies each object at the origin before it drops the inline copy, and never half-rewrites a page. - The way back ships with the page. The agent footer (step 3) is not decoration and is not
the hook's job — the hook only sees writes it can attribute, and a page written by heredoc,
cp, or a script carries no path for it to attribute. Write the footer; then it does not matter whether anything noticed. - Metadata is part of the artifact. The five
intranet:*meta tags (step 3) and the PROVENANCE block ship on every page, no exceptions — they are how the intranet index files the page without guessing. A page missing them is unfinished. - Tokens, not hard-codes. All brand color/font decisions live in
:rootcustom properties so a re-brand is a few-line edit. - Don't fabricate data. Render only what's in the source content; never invent metrics.
- Don't fabricate tokens either. A colour, font, or logo you chose by feel is fabricated
design data, and it is harder to spot than a fabricated number because a
:rootblock looks authoritative by construction. Every token traces to a rung, or the page is declared unbranded. - State the brand and the provenance in chat, not only in a CSS comment. The user cannot see your reasoning, and a wrong-but-plausible palette is invisible to them until they ask.
- Lightweight. No JSON data model, no logo pipeline, no build step beyond the deploy. The only script is the deterministic deploy.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

