SuperAPI AI Directory

zenstory

Writing & research

View repository

Updated 10-16 10:45

About this skill

zenstory

zenstory is an AI-assisted novel writing workbench. Everything in a project is a file (outline, draft chapter, character, lore, material, folder) arranged in a folder tree. This skill operates those files with the zenstory CLI, which wraps the public Agent API.

Running the CLI

Use zenstory ... if it is installed (command -v zenstory). Otherwise use npx -y zenstory ... with exactly the same arguments. Examples below use zenstory.

Always add --json when you need to parse output. Errors go to stderr; the exit code tells you what happened: 0 ok, 2 usage error, 3 auth/permission, 4 not found, 5 rate limited, 1 anything else.

Setup check (do this first, once per session)

zenstory whoami --json
  • Exit 0: note scopes.read / scopes.write. Without write, you can only read — tell the user before planning edits.

  • Exit 3 ("Not logged in" / key rejected): ask the user to create an Agent API key in zenstory → Settings → Agent (enable the write scope if they want you to edit), then run this themselves in their own terminal and paste the key when prompted (input is hidden, so the key stays out of shell history):

    npx -y zenstory login
    

    Self-hosted zenstory: add --api-base https://<their-server>/api/v1.

  • Never ask the user to paste the key into the chat, and never put a key on a command line. If they already pasted a key into the chat, treat it as exposed: recommend they regenerate it in Settings → Agent and log in again with the new key as above. Never echo, log or repeat a key.

Orient in a project

zenstory projects list --json                 # pick the project id
zenstory files tree <projectId>               # folders + titles + ids, no content
zenstory files list <projectId> --type draft --json   # chapters (content omitted)

Every project (created in the web app or with zenstory projects create) starts with root folders whose ids are predictable, e.g. <projectId>-draft-folder (Body/Drafts), <projectId>-outline-folder (Outline/Outlines), <projectId>-character-folder (Character/Characters), <projectId>-lore-folder (Setting/World Building), <projectId>-material-folder (Material/Materials); screenplays use <projectId>-script-folder. projects create prints them. The user may have renamed, deleted or nested folders, so confirm with files tree before relying on them. See references/concepts.md for file types, folders per project type, and what writing-context returns.

Workflow: continue or revise a chapter

  1. Find the chapter: zenstory files list <projectId> --type draft --json (or search).
  2. Gather context before writing:
    zenstory context <projectId> --file <chapterId> --query "what happens next" --json
    
    This returns AI-ranked snippets (parent outline, previous chapter, characters, lore, retrieved passages). Open any item you need in full with zenstory files get <source_file_id>.
  3. Note the chapter's current updated_at, then read it into a private temp directory (use one directory per session and name files by file id):
    zenstory files get <chapterId> --fields id,title,updated_at --json   # note updated_at
    dir=$(mktemp -d)
    zenstory files get <chapterId> -o "$dir/<chapterId>.md"
    
  4. Edit $dir/<chapterId>.md (keep the user's existing text unless asked to rewrite it).
  5. Save, passing the updated_at you noted so the write is refused if the user changed the chapter in the browser meanwhile:
    zenstory files put <chapterId> --content-file "$dir/<chapterId>.md" \
      --if-updated-at <updated_at> --json
    
    If it fails with "changed on the server", re-read, re-merge, and retry with the new updated_at. The server records a version of every content change unless the plan's per-file version quota is full (see Undo); the CLI also saves the previous content locally and prints backupPath as a second safety net.

files put replaces the whole content. Never put a partial chapter or a summary back. It refuses content shorter than half of the current text unless you pass --allow-shrink — only do that after the user confirmed the cut.

Workflow: write a new chapter

zenstory context <projectId> --query "chapter 13: the duel at the pass" --json
# write the chapter to "$dir/ch13.md" (dir=$(mktemp -d)), then:
zenstory files create <projectId> --type draft --title "第十三章 关山对决" \
  --parent <projectId>-draft-folder --order 13 --content-file "$dir/ch13.md" --json

Match the title pattern of existing chapters (look at files list --type draft) and pass --order <chapter number> so chapters sort in reading order (without it the new file goes after its last sibling; chapter titles like 第N章 / Chapter N always sort by N). For a chapter outline use --type outline under the outline folder. Fix the order of an existing file with files put <fileId> --order <n>.

Workflow: characters, lore and materials

zenstory search <projectId> "林远" --type character --json      # avoid duplicates first
zenstory files create <projectId> --type character --title "林远" \
  --parent <projectId>-character-folder --content-file "$dir/linyuan.md" \
  --metadata '{"role":"protagonist"}' --json
zenstory files create <projectId> --type lore --title "灵脉体系" \
  --parent <projectId>-lore-folder --content-file "$dir/lingmai.md" --json

Materials (Material) use file type snippet (--type material is accepted as an alias). --parent must be a folder in the same project. To tidy a file that sits in the wrong place (e.g. at the project root), move it: zenstory files move <fileId> --parent <projectId>-character-folder (--parent root moves it to the top level). Create extra folders (e.g. one per volume) with files create --type folder --title "第一卷".

Workflow: continuity check

zenstory search <projectId> "玉佩的来历" --limit 10 --json
zenstory search <projectId> "Chen's scar" --type draft --type outline --json

Results carry id, title, file_type, snippet, line_start and score. Open the source with files get <id> before asserting a fact. Newly written files are indexed in the background, so a just-saved change may take a moment to appear in search.

Undo a change

Every content change made through the CLI (and the web editor) is recorded as a version, unless the plan's per-file version quota is full: then the content is still saved, the CLI prints a warning (version_quota_exceeded: true in --json) and only the local backupPath copy of the previous content remains. Tell the user when that happens.

zenstory files versions <fileId> --json            # newest first, no content
zenstory files version <fileId> <n> -o "$dir/<fileId>-v<n>.md"   # inspect version n
zenstory files rollback <fileId> <n> --yes --json  # restore it; prints new_version_number

A rollback keeps the history: the restored content becomes a new version, so it can be undone too. Ask the user before rolling back. If new_version_number is null, the content was restored but no new version was recorded — because the per-file version quota is full when version_quota_exceeded is true, otherwise because the snapshot could not be saved. Files created with content through the CLI start at version 1; the local backupPath copies from files put remain a second net (e.g. for files whose history started before the CLI touched them).

Safety rules

  • Confirm before destructive actions. Ask the user before files delete / projects delete / files rollback (all need --yes) and before files put that would shrink or replace substantial existing text (e.g. more than a few paragraphs). Show what will change.
  • Read before you write. Never overwrite a file you have not just read; always pass --if-updated-at to files put.
  • Respect rate limits (per key, per hour): read 2000, write 1000, search 500, writing-context 500. Use files list --fields / files tree instead of fetching every file's content, don't poll, and stop on exit code 5 and tell the user.
  • Keep secrets out of output. The CLI masks the key; never print config files or environment variables that contain it.
  • Stay in scope. Only touch the project the user named. If a command fails with exit 3 on write, the key likely lacks the write scope or is limited to other projects — report it instead of retrying.
  • Prefer --json for anything you parse; use human output only to show the user.

Reference