agentleFS
wwwyowwwyo/syokan/skills/syokan/SKILL.md

syokan

Skill0 starsChanged 19 days agoMITView on GitHub

Build and POST a JSON snapshot envelope to syokan (召喚 — a verb: summon data into a rich, living view). Use when the user says \"syokan this\", \"syokan X\", \"show in syokan\", \"post a snapshot\", \"preview this markdown\", or in Japanese 『〜を syokan』『syokan に出して/表示して/投げて』『snapshot を作って/送って』『syokan のUIで見たい』『Markdown をプレビューして/md ファイルをブラウザで見たい』 — for RSS feeds, in-progress PR reviews, review risk panels, meeting notes, today's TODO, dashboards, or any aggregated data the user wants to see as structured UI. Whenever the word syokan appears, use this skill even if the user does not explicitly say snapshot.

The file

We split this skill into the rules it gives an agent

7 rules. About 0 are common, 2 are distinctive, and 5 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈2

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 5

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Leaves cannot have children: only containers (Stack, Card, Checklist, Collapsible) accept children.

    line 20
  2. Very specific:

    Check the available types and props with syokan catalog (see "Catalog" below).

    line 25
  3. Distinctive:

    If you have built a similar view before, do not start from scratch — base it on a saved template (see "Templates for reproducibility" …

    line 32
  4. Very specific:

    Only the following may go in the POST body.

    line 36
  5. Very specific:

    Never include id, createdAt, or url — the server assigns them.

    line 37
  6. Very specific:

    Do not rebuild a favorite view from scratch every time — save it as a template in syokan and reuse it.

    line 123
  7. Distinctive:

    If a matching template exists, do not build from zero: find the id in the list → fetch it → swap in the data → post.

    line 126

≈ “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.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

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 views: only put reconstructible, transient data there (today's RSS, an in-progress review, etc.). Deleting a view archives it rather than destroying it (see "Looking back at past snapshots" below), but the archive is a record, not a place to keep things on purpose. For layouts you reuse, save a template to reproduce them (templates persist — see "Templates for reproducibility" below).
  • JSON only — no free-form markdown ingest: the server accepts nothing but a JSON envelope; you can't POST a raw .md file. Markdown is a catalog node like any other, and it is deliberately restricted to prose flow: paragraphs, plain bullet/numbered lists (nested ok), bold/italic/strikethrough, inline code, fenced code, blockquotes, links. Block structure and data still belong to their own node — the server 400s a Markdown body containing a heading (use Heading), a GFM table (Table), a task-list item (Checklist), raw HTML, an image, or a non-http(s) link, naming the replacement in the error. A ```mermaid fence inside Markdown renders as a plain code block, not a diagram — put diagrams in their own Mermaid node. For anything outside that prose subset, structure it into catalog nodes yourself: headings → Heading, code fences needing their own filename/copy affordance → Code, mermaid fences → Mermaid, preformatted or verbatim text outside prose (raw logs, ASCII tables) → Code with no lang.
  • Strict schema: props are validated strictly. Keys not in the schema are rejected — do not invent extra keys.
  • Leaves cannot have children: only containers (Stack, Card, Checklist, Collapsible) accept children; check childrenTypes in syokan catalog. Attaching children to a leaf node is rejected at ingest.
  • Probes are predefined checks only: Probe.check must be one of the kinds accepted by Probe's check props schema (see syokan catalog). There is no way to run an arbitrary command from a view — do not try.

From composing to viewing

  1. Check the available types and props with syokan catalog (see "Catalog" below).
  2. Map the data you want to show onto those components. The top level is usually a container (Stack etc.) stacking items vertically.
  3. Turn it into an envelope JSON (see "Envelope shape" below). Only root is required.
  4. Post it with the CLI (see "Posting" below). On success the view URL is printed.

Write the view's own text (headings, verdicts, explanations, captions) in the language the user addressed you in. The docs and the catalog are English, but the view is for the reader, and an English panel handed to a Japanese-speaking reader is a defect, not a default.

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
  "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
}

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", "notes" }], "envelope": <JSON Schema for the envelope's own keys> }.

  • props: the type's props as JSON Schema. Satisfy required / enum / format (httpUrl is uri, Time.datetime is date-time) / additionalProperties:false (unknown keys are rejected) exactly as given. Probe's check props schema is where its predefined check kinds live.
  • childrenTypes: null means a container that accepts children, [] means a leaf that accepts none, [..] means only the listed types may be children.
  • notes: usage contract the props schema can't express (e.g. Checklist pairs children[i] with items[i]). Read it before using a type.
  • envelope: the JSON Schema for the envelope's own keys (root / title / schemaVersion / idempotencyKey) — the SSOT for "Envelope shape" above. root is left opaque there; what may go inside it is items, so a body is valid only when it satisfies both.

For complete examples combining the components, see references/examples.md.

Spacing (Stack)

Stack spaces its children by nesting depth: the outermost stack separates sections, and each level further in tightens the spacing (deeper than three levels stays at the tightest). Leave gap unset — that default is what keeps views from drifting apart visually. Set it (none / sm / md / lg) only when the depth-derived spacing is wrong for a specific group, e.g. none for a row of items meant to read as one strip. A horizontal Stack scrolls inside itself when its children exceed the width, so lining many up never breaks the page.

Card is not the default container

The default flow is Heading + body nodes inside a Stack; a Heading can carry the id that jump links target. Reach for Card only when a unit needs a visible boundary to be read as one thing — items the reader compares side by side, or a block that must stand apart from the surrounding flow. Wrapping every list item or section in a Card adds borders and padding without adding meaning, and makes long views heavier to scan.

Cross-cutting node field (id)

Besides type / props / children / key, any node may carry id: it makes the node addressable. A Link with href: "#<id>" jumps to it inside the view (revealing it if folded). It is also the identity for UI state — give an id to every Checklist / Collapsible / Probe so checks, folds, and probe reruns survive reloads. An id must be unique tree-wide; a duplicate 400s.

On an id-carrying Checklist, a check on the view is written back into the snapshot itself (PATCH /api/snapshots/:id) — progress survives reloads, shows up on other devices, and lands in published shares. The writeback is a conditional set on the item's checked, identified by label (same-label items by occurrence order), so you may reorder or insert items when you regenerate the tree and checks still land on the item the reader meant — but keep each item's label stable: a rewritten label breaks the correspondence and the reader's writeback is refused. A Checklist without an id keeps device-local checks (viewer's browser only) as before, so an id-less Checklist's progress never reaches the store. For Collapsible folds and Probe re-runs, state lives in the viewer's browser — post the initial state (checked, defaultOpen, result) and let the reader take it from there.

Interactive views (risk panels, TODO, dashboards)

For status/risk panels of any kind (PR review, deploy status, incident dashboards), see references/risk-panel.md, which lists the aspects worth showing and the recommended node for each — the panel structure is yours to decide. A minimal working example is references/examples.md Example 5.

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). The pipe form is agent-neutral — any agent that can emit the JSON as text (Codex, pi, Devin, a scheduled script) can post the same way.

For everything else — commands, subcommands, env vars, exit codes — consult syokan --help --json; for types and props, syokan catalog.

Posting a tree file

To iterate on a view from a file, write the catalog tree to a JSON file and syokan the path. A file holding a bare catalog tree ({ "type": ..., "props": ... }, no envelope) is inlined into a self-contained snapshot — title = the file name, idempotencyKey = file:<absolute path> — so re-running the same command updates the same view in place, and an open view follows the update without a reload.

syokan ./dashboard.json   # post; edit the file and re-run to update the same view
  • syokan <path> accepts JSON only: a file holding an envelope posts the envelope as-is; a bare catalog tree posts inline; anything else (markdown / log / txt / other JSON) is rejected with unsupported_input.
  • The snapshot holds the file's content at invocation time — nothing references the file afterward. Renaming or moving the file names a new view.
  • The same goes for any envelope you post: every view is the stored snapshot, period — updating means PUT/PATCH into the store, never pointing a view at a live file.

To show a local markdown / text file, there is no file viewer: read it and post the result as catalog nodes (see "JSON only — no free-form markdown ingest" above). Prose sections (paragraphs, lists, links, fenced code, blockquotes) can go straight into a Markdown node's body; pull out headings into Heading, GFM tables into Table, and task lists into Checklist first — Markdown rejects those. For raw text, jq --rawfile streams a body in without worrying about JSON escaping.

jq -n --rawfile body app.log \
  '{title:"app.log", root:{type:"Code",props:{code:$body}}}' \
  | syokan

Looking back at past snapshots

Deleting a snapshot (the sidebar's delete, or DELETE /api/snapshots/:id) archives it: it leaves the list and its view shows not-found, but the envelope — including checks the reader wrote back — stays readable. Use this to answer "what did I look at / finish yesterday?" from the store instead of digging through files:

syokan snapshots list --since 2026-06-27 --until 2026-06-27            # active snapshots created that day
syokan snapshots list --archived --since 2026-06-27 --until 2026-06-27 # archived ones (archivedAt set)
syokan snapshots get <id>                                              # full envelope, active or archived — no flag needed
  • --since / --until are inclusive local calendar days on createdAt. Query both the active list and --archived when you need the whole day.
  • An archived snapshot is read-only. Re-posting with the same idempotencyKey (e.g. re-running syokan ./daily.json) brings it back under the same id/URL with the newly posted content; the archive keeps the old copy, and old checks are not carried over.
  • syokan snapshots purge <id> permanently deletes an archive record — irreversible, and it only works on archived records (an active snapshot must be deleted first). Do not purge unless the user asks for it.

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.

Download now (ZIP)

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
What did you use it for? e.g. Reviewing pull requests in a Rails app

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.