Skip to main content

ghostex-visuals

Ghostex visuals (gx visuals): charts, stat tiles, tables and text layouts in the Ghostex chat with a fenced ```visual block. Ghostex forms (gx form): questions for the reader as a form in the chat with a ```questions block. Ghostex pages (gx page): self-contained HTML pages (UI mockups, small interactive tools, questions that need a picture) published with `ghostex show`, which the chat shows as a card that opens the page. Use only when the user asks for $ghostex-visuals, a Ghostex page, form or visuals, or a gx page, gx form or gx visuals.

Source facts

Repository
maddada/Ghostex
Last source activity
November 11, 2026 at 02:59
Detected SKILL.md language
English
Stars
1,652
Forks
135

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
3 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
ghostex-visuals
description
Ghostex visuals (gx visuals): charts, stat tiles, tables and text layouts in the Ghostex chat with a fenced ```visual block. Ghostex forms (gx form): questions for the reader as a form in the chat with a ```questions block. Ghostex pages (gx page): self-contained HTML pages (UI mockups, small interactive tools, questions that need a picture) published with `ghostex show`, which the chat shows as a card that opens the page. Use only when the user asks for $ghostex-visuals, a Ghostex page, form or visuals, or a gx page, gx form or gx visuals.
disable-model-invocation
true
# ghostex-visuals Ghostex draws what you put in your reply natively in the chat, on desktop, web and phone. Each kind has a name; the user uses these names, and so do you when you talk to them ("I made a Ghostex page", "answer the Ghostex form"): | Name | Short | What you write | Older words for it | | --- | --- | --- | --- | | Ghostex visuals | gx visuals | a ```visual block: charts, graphs, stats, tables, text layouts | inline graphs, inline charts | | Ghostex form | gx form | a ```questions block, or one-click answers for a quick pick | inline questions, inline q, question form | | Ghostex page | gx page | a self-contained HTML page published with `ghostex show` | inline HTML, chat page, HTML page | "Give me a gx page for this" means a Ghostex page, "ask me in a gx form" a Ghostex form, "show it as gx visuals" a ```visual block. - Prefer Ghostex visuals for charts, tables, stats and text layouts. - Ask questions in a Ghostex form: the chat shows a ```questions block as a form. - Use a Ghostex page only for what a block cannot express: UI mockups, small interactive tools, and questions the reader can only answer by seeing a picture. - Don't restate in prose what the visual already shows. Add only what it doesn't: the conclusion, a caveat, the next step. ## Ghostex visuals: ```visual blocks One JSON object in a fence whose info string is `visual`. The block is one of: - **A Vega-Lite spec** at the top level: an object with `"mark"`. It may have `"title"` and `"height"`. - **A composition**: `{"title"?: "…", "rows": [part, …]}`, drawn top to bottom. A part is one of the following, and every part may have `"title"`: - `{"chart": <Vega-Lite spec>}` - `{"stats": [{"label": "…", "value": "…", "note"?: "…", "tone"?: "good" | "bad" | "neutral"}]}` (`value` may be a number) - `{"table": {"columns": ["…", …], "rows": [["…", …], …]}}`, or rows as objects keyed by column name (then `"columns"` is optional) - `{"text": "…"}` - `{"columns": [part, …]}`: parts side by side - **A page**: `{"page": {"title": "…", "url": "…"}}`. Only ever paste this from `ghostex show` output (below); never write one yourself. ### The Vega-Lite subset - `mark`: `bar`, `line`, `area`, `point` (also `circle`, `square`), `arc` (pie; `{"type": "arc", "innerRadius": 50}` for a donut). The object form `{"type": "line", "point": true}` adds points to a line. - Encoding channels: `x`, `y`, `color`, `theta`, `tooltip`, `xOffset` (grouped bars). - Field definition keys: `field`, `type` (`quantitative`, `nominal`, `ordinal`, `temporal`), `aggregate` (`sum`, `mean`, `count`, `min`, `max`, `median`), `title`, `sort` (`"ascending"`, `"descending"`, `null` for data order, or an array of values), `axis` (`null` to hide it, or `{"title": …}`), `scale` (`{"domain": [min, max], "zero": false}`), `stack` (`null`/`false`, `true`, `"normalize"`). - Data only as `"data": {"values": [ … ]}` with the rows inlined; `data.url` isn't supported. Aggregate large data before writing the block. - Not supported: `layer`, `facet`, `repeat`, `concat`, `transform`, `params`/selections, `bin`, and the `rule`, `text`, `tick` and `rect` marks. Compute bins, totals or moving averages into the rows yourself. - The width always fits the chat column; `"height"` sets the chart height (100 to 600). ### Check the block before replying Write the JSON to a temporary file and draw it: ```bash ghostex visual check /tmp/block.json # prints a PNG path, or names the problem ghostex visual check /tmp/block.json --light # light theme ghostex visual check /tmp/block.json --width 360 # phone width ``` Look at the PNG, fix what reads badly, then paste the same JSON into your reply. If `ghostex visual` is an unknown command, this Ghostex is too old to check: skip the check. ### Examples Grouped bars: ```visual { "title": "Build time by platform", "mark": "bar", "height": 220, "data": {"values": [ {"platform": "macOS", "build": "debug", "minutes": 4.2}, {"platform": "macOS", "build": "release", "minutes": 9.8}, {"platform": "Windows", "build": "debug", "minutes": 5.1}, {"platform": "Windows", "build": "release", "minutes": 12.4}, {"platform": "Linux", "build": "debug", "minutes": 3.6}, {"platform": "Linux", "build": "release", "minutes": 8.9} ]}, "encoding": { "x": {"field": "platform", "type": "nominal", "sort": null, "axis": {"title": null}}, "xOffset": {"field": "build"}, "y": {"field": "minutes", "type": "quantitative", "title": "Minutes"}, "color": {"field": "build", "type": "nominal", "title": "Build"} } } ``` For stacked bars, drop `xOffset`; bars that share an `x` stack by `color`. A line chart with two series: ```visual { "title": "Response time", "mark": {"type": "line", "point": true}, "data": {"values": [ {"day": "2026-10-01", "series": "p50", "ms": 120}, {"day": "2026-10-02", "series": "p50", "ms": 118}, {"day": "2026-10-03", "series": "p50", "ms": 131}, {"day": "2026-10-01", "series": "p95", "ms": 340}, {"day": "2026-10-02", "series": "p95", "ms": 310}, {"day": "2026-10-03", "series": "p95", "ms": 365} ]}, "encoding": { "x": {"field": "day", "type": "temporal", "title": "Day"}, "y": {"field": "ms", "type": "quantitative", "title": "Milliseconds"}, "color": {"field": "series", "type": "nominal", "title": "Percentile"}, "tooltip": [{"field": "day", "type": "temporal"}, {"field": "ms", "type": "quantitative"}] } } ``` Stats above a table: ```visual { "title": "Test run", "rows": [ {"stats": [ {"label": "Passed", "value": 412, "tone": "good"}, {"label": "Failed", "value": 3, "note": "all in sync/", "tone": "bad"}, {"label": "Duration", "value": "2m 41s"} ]}, {"title": "Failures", "table": { "columns": ["Test", "Error"], "rows": [ ["sync::resume_after_sleep", "timed out after 30s"], ["sync::merge_conflict", "expected 2 rows, got 3"], ["sync::large_file", "permission denied"] ] }} ] } ``` ## Ghostex forms: ```questions blocks When you need the reader's decisions, put the questions in a ```questions block in your reply. The chat draws it as a form under your message, on desktop, web and phone: every question at once, choices picked with a click, a note box per question, and one Send button. Use it instead of asking in prose or as a numbered list, and instead of your agent's own question tool (AskUserQuestion and the like), which shows one question at a time. Only when the reader has to see something to answer (a UI mockup, a layout, a diagram) use a Ghostex page with questions instead (see "Ghostex pages with questions" below). First run `ghostex visual --help`: if it doesn't mention ```questions, this Ghostex can't show the form, so ask in prose instead. ### One-click answers One quick pick with 2 to 4 short answers and nothing to explain or note (a yes/no, "merge it?", "delete the branch?") needs no form: write the answers right after the question, one Markdown link per answer pointing at `ghostex-answer:` and the question's tag. Only when `ghostex visual --help` mentions `ghostex-answer:`; older versions show plain links. ```markdown ❓ **Needs you:** - [PR #414](https://github.com/owner/repo/pull/414): Review and merge it? [Yes](ghostex-answer:Q901) [No](ghostex-answer:Q901) [Later](ghostex-answer:Q901) - Temporary branch `fix/tab-drag`: Delete it? [Delete](ghostex-answer:Q902 "recommended") [Keep](ghostex-answer:Q902=keep) ``` - The link's text is the answer. `=value` sends a value other than the label; the title `"recommended"` marks the one you recommend. - The question is the line's words before its first answer link. Keep the links on the question's own line, and keep it one line. Links on a line or sub-bullet of their own take the nearest line above that names their tag (else their parent bullet) as the question. - The chat draws the answers as a small pill under the question. One tap sends them back as a normal message in the same envelope a form's answers use, keyed by the tag, with the question as its title: `<ghostex-page-answers page="…" title="PR #414: Review and merge it?">{"Q901": "Yes"}</ghostex-page-answers>`. The reader may change a sent answer: a change that reaches you after the first arrives with `"Q901 (note)": "Changed from Yes"`. - Tags count up with the forms' tags. The "?" pill counts an inline question until it is answered, and a later ```questions block can withdraw its tag. - Use a form instead for several related questions, multi-select, a text answer, choices that need a line of detail, or anything the reader may want to add a note to. ```questions { "title": "Settings redesign: layout and platforms", "questions": [ {"tag": "Q1", "title": "Which layout should I build?", "detail": "Why it matters, in a sentence or two.", "choices": [ {"label": "Tabs", "detail": "One page per area.", "value": "tabs", "recommended": true}, {"label": "One long page", "value": "one page"} ]}, {"title": "Which platforms first?", "multiple": true, "choices": ["macOS", "Windows", "Phone"]}, {"title": "What should the new page be called?", "type": "text"} ] } ``` - Always give the form a `title`: a short, specific name for what it asks, such as "Settings redesign: layout and platforms". Ghostex lists every open form and page by this name (the chat's "?" pill shows them under Unanswered, For later and Answered), so a generic title ("Questions", "Decisions", "A few questions") can't be told apart from the others. `submit` renames the button ("Send answers"). - Each question: `title`; `detail`, a short explanation; `tag`, an optional short label such as an issue id; `name`, the answer's key (the title when there is none); `multiple` for several picks; `type: "text"` for a text box instead of choices (`placeholder` sets its hint). At most 20 questions. - Link what you ask about: when a question is about a PR, issue, file, page, commit, thread or anything else the reader could open, link it in the question itself, so they can check it before answering. Write a Markdown link with the full URL (`[#407](https://github.com/owner/repo/pull/407)`) or a file path link (`[kit.rs](/abs/path/kit.rs)`) in the `title` or
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub