syokan은(는) 무엇을 하나요?
syokan (召喚, "summon") is a verb — LLMs summon rich UI. When the user says "syokan X" (JA: 「Xを syokan」), that is a request to summon that data into a view. Under the hood it is a schema-driven view layer: instead of writing JSX, you speak a JSON incantation — a tree of catalog components — and syokan renders it with predefined components. Your job is to assemble the data into an envelope and POST it to syokan. In prose, use syokan as a bare transitive verb (never "do syokan" / never 「syokan する」 — syokan stands on its own).
If syokan is not installed yet (syokan --help fails), or the user says "onboarding", "set it up", or "first time using it", walk them through references/onboarding.md up to their first snapshot. Do not silently run environment-changing operations such as installs: report that it is not installed and get the user's approval before executing (never install on your own).
Non-negotiables
- Snapshots are ephemeral: a posted snapshot has no persistence guarantee. Only put reconstructible, transient data there (today's RSS, an in-progress review, etc.). For layouts you reuse, save a template to reproduce them (templates persist — see "Templates for reproducibility" below).
- JSON only: the server accepts nothing but a JSON envelope. Raw markdown or plain text is rejected. To show prose, wrap it in a
MarkdownDocorPlainTextnode. - Strict schema: props are validated strictly. Keys not in the schema are rejected — do not invent extra keys.
- Leaves cannot have children: only
StackandCardaccept children. Attaching children to a leaf node is rejected at ingest.
From composing to viewing
- Check the available types and props with
syokan catalog(see "Catalog" below). - Map the data you want to show onto those components. The top level is usually a container (
Stacketc.) stacking items vertically. - Turn it into an envelope JSON (see "Envelope shape" below). Only
rootis required. - Post it with the CLI (see "Posting" below). On success the view URL is printed.
If you have built a similar view before, do not start from scratch — base it on a saved template (see "Templates for reproducibility" below).
Envelope shape
Only the following may go in the POST body.
Never include id, createdAt, or url — the server assigns them.
{
"root": { "type": "Stack", "props": {}, "children": [ /* catalog nodes; full examples in references/examples.md */ ] }, // required. the view tree
"title": "Today's RSS", // optional. shown in the list and the view header
"metadata": { "source": { "label": "daily-rss" } }, // optional. provenance label
"schemaVersion": 1, // optional. server fills it in
"idempotencyKey": "rss-2026-06-28" // optional. names this view so it can be refreshed later instead of duplicated
}
metadata.source keeps extra keys beyond label; you may add url or fetchedAt (e.g. { "label": "gh-review", "url": "https://example.com/..." }).
For daily or recurring views, include something like the date in the idempotencyKey. The syokan CLI handles the rest: it targets that key first, and only creates a new view if none exists yet — so the first post creates the view and every later post with the same key refreshes that same view in place instead of duplicating it. You don't need to track whether it's the first post yourself. (If you call the HTTP API directly instead of the CLI: POST /api/snapshots always creates and tags the key; PUT /api/snapshots targets an existing key and 404s if it's not there yet — there is no create-on-miss endpoint, which is why the CLI tries PUT first and falls back to POST on a 404.)
Catalog
Get the available types and their props definitions from syokan catalog (never transcribe them into md — pull them from here every time).
The output is { "items": [{ "type", "props", "childrenTypes" }] }.
props: the type's props as JSON Schema. Satisfyrequired/enum/format(httpUrl isuri,Time.datetimeisdate-time) /additionalProperties:false(unknown keys are rejected) exactly as given.childrenTypes:nullmeans a container that accepts children,[]means a leaf that accepts none,[..]means only the listed types may be children.
For complete examples combining the components, see references/examples.md.
Posting
Pass the assembled envelope as a file or via stdin; on success the view URL is printed to stdout (syokan snapshot.json / cat snapshot.json | syokan / claude -p '…JSON…' | syokan).
For everything else — commands, subcommands, env vars, exit codes — consult syokan --help --json; for types and props, syokan catalog.
Previewing local files
For a local file, syokan <path> is the shortest route — you syokan the file itself. Envelope JSON is posted as-is; anything else (markdown / log / txt / json, ...) is auto-wrapped in a live FileDoc. The CLI resolves it to an absolute path and hands it to the server, which reads the content and infers the format from the extension (.md/.markdown → markdown, .json → code, everything else → text). While the view is open it follows edits to the file (no re-posting needed).
syokan notes.md # renders markdown; the view refreshes on every save
syokan app.log # shows a growing log in monospace
To combine multiple files into one view, or mix them with Heading and other nodes, place FileDoc nodes yourself (props: path, absolute paths only; FileDoc handles reading and change tracking).
Conversely, to show a file's content frozen statically (no follow-up needed, or you are transforming the content), put the body into a MarkdownDoc / PlainText / Code node. jq --rawfile streams it in without worrying about JSON escaping.
jq -n --rawfile body README.md \
'{title:"README.md", root:{type:"Stack",props:{},children:[{type:"MarkdownDoc",props:{body:$body}}]}}' \
| syokan
Templates for reproducibility
Do not rebuild a favorite view from scratch every time — save it as a template in syokan and reuse it.
A template is "the saved envelope itself". You may put markers like {{...}} in the skeleton and fill them in yourself.
If a matching template exists, do not build from zero: find the id in the list → fetch it → swap in the data → post. When you produce a new view worth keeping, save it and reproduce it next time. For subcommand syntax (templates list|add|get|rm), consult syokan --help --json.