Felo SuperAgent Skill
Constraints (MUST READ FIRST)
These rules are mandatory. Violating any of them will produce incorrect behavior.
- 1. ALWAYS use
--json flag. The script MUST run in JSON mode (--json). In Claude Code's Bash tool, stdout is always captured — it never streams directly to the user. JSON mode returns the full answer in a structured response that Claude can then output as text. State IDs are extracted from the JSON response fields thread_short_id and live_doc_short_id.
- 2. ALWAYS output the answer directly as text. After the script finishes, read
data.answer from the JSON output and print it verbatim as your response text. Do NOT summarize, paraphrase, or add commentary around it. Output it exactly as-is so the user sees the full content. Then, if data.image_urls is non-empty, append image links immediately after, formatted as one line per image: [title](url).
- 3.
--live-doc-id is REQUIRED when creating a conversation. Never call run_superagent.mjs without --live-doc-id. If you do not have one yet, obtain it first (see Step 2 below).
- 4. Reuse
live_doc_id from ANY source. If you already have a live_doc_id from any previous operation in this session — whether from a prior SuperAgent call, a felo-livedoc skill operation, user-provided input, or any other skill — use it directly. Do NOT request the LiveDoc list again. Only fetch the list when no live_doc_id is available from any source. (Note: live_doc_id corresponds to the API field live_doc_short_id and the [state] output key live_doc_short_id.)
- 5. One LiveDoc per session. All conversations within a session MUST use the same
--live-doc-id. Do NOT create a new LiveDoc unless the user explicitly asks to "open a new canvas" / "start a new LiveDoc" / "create a new workspace".
- 6. Default behavior is follow-up, not new conversation. After the first question, every subsequent user message is a follow-up. You MUST pass
--thread-id from the previous response. Only omit --thread-id (to start a new thread on the same LiveDoc) when:
- The user explicitly says "new topic" / "change subject" / "start over"
- The user's intent requires a specific
--skill-id (e.g., tweet writing, logo design, product image) and the current thread was not created with that skill — because
--skill-id only takes effect in new conversations
- 7. Always persist state. After every call, extract
thread_short_id and live_doc_id from the stderr [state] line (where live_doc_id is output as live_doc_short_id). Use them in the next call. Losing these IDs breaks conversation continuity.
- 8. Skill ID selection (New Conversations Only). When creating a new conversation (no
--thread-id), analyze the user's intent and determine if it matches one of the supported skill IDs:
Available skill IDs:
- twitter-writer — For composing, drafting, or posting tweets/X posts
- logo-and-branding — For creating logos, brand designs, or visual identity
- ecommerce-product-image — For generating product images for e-commerce use
Selection logic:
- If the user explicitly requests a specific skill-id, use their specified value
- If the user's intent clearly matches one of the above, pass --skill-id with that value
- If none of the above match, do NOT pass --skill-id (general conversation mode)
- --skill-id is only effective when creating a new conversation. It is ignored in follow-up mode (--thread-id).
- 9. Brand style selection for skill-based new conversations. When starting a NEW conversation that uses a skill ID (
twitter-writer, logo-and-branding, ecommerce-product-image), you MUST fetch the style library and let the user choose a style BEFORE calling run_superagent.mjs. The chosen style is passed via --ext '{"brand_style_requirement":"<style_string>"}'. See Step 4.5 for the full procedure.
- The style string is the exact text block output by run_style_library.mjs for that entry. Fields vary by category:
- TWITTER: Style name + Style labels (language-aware) + Style DNA + Cover file ID (omitted if null)
- IMAGE: Style name + Style labels + Style DNA or Cover file ID depending on what is present
- Use the category that matches the skill: TWITTER for twitter-writer, IMAGE for logo-and-branding and ecommerce-product-image.
- Always pass --accept-language to run_style_library.mjs so labels are returned in the user's language.
- If the user has already specified a style (by name or by pasting the style block), skip the fetch and use their choice directly.
- If the style library returns no entries, proceed without --ext.
- --ext is only valid for new conversations. Never pass it in follow-up mode (--thread-id).
- 10. Never create a new LiveDoc casually. Reuse the existing one. The only exception is an explicit user request for a new canvas/workspace.
When to Use
Trigger this skill when users want:
- - SuperAgent conversation: AI conversation with Felo SuperAgent, with real-time streaming output
- Continuous conversation: Multi-turn Q&A on a persistent LiveDoc canvas
- Logo & branding: Create logos or brand designs (auto-selects
logo-and-branding skill) - E-commerce images: Generate product images (auto-selects
ecommerce-product-image skill) - Tool-augmented answers: Responses that may include image generation, document creation, PPT generation, or Twitter/X search
- Streaming responses: Real-time answer generation with Server-Sent Events (SSE)
Trigger words:
- - English: superagent, super agent, stream chat, streaming conversation, livedoc conversation, continuous chat, follow-up question, create a logo, brand design, product image, e-commerce image
- Simplified Chinese (pinyin): chao ji zhu shou, liu shi dui hua, lian xu dui hua, zhui wen, she ji logo, pin pai she ji, dian shang tu pian
- Traditional Chinese (pinyin): chao ji zhu shou, liu shi dui hua, lian xu dui hua, zhui wen, she ji logo, pin pai she ji, dian shang tu pian
- Japanese (romaji): suupaa eejento, sutoriimingu kaiwa, keizoku kaiwa, rogo sakusei, shouhin gazou
Explicit commands: /felo-superAgent, "use felo superagent", "felo superagent"
Do NOT use for:
- - Tweet/X post writing of any kind (use
felo-twitter-writer instead) - Simple one-off Q&A or real-time information queries (prefer
felo-search) - Web page content fetching only (use
felo-web-fetch) - PPT/slide generation only (use
felo-slides) - LiveDoc knowledge base management only (use
felo-livedoc) - Twitter/X search only (use
felo-x-search)
Setup
1. Get Your API Key
- 1. Visit felo.ai and log in (or register)
- Click your avatar in the top right corner → Settings
- Navigate to the "API Keys" tab
- Click "Create New Key" to generate a new API Key
- Copy and save your API Key securely
2. Configure API Key
The scripts (run_superagent.mjs, run_style_library.mjs) read the API key only from the FELO_API_KEY environment variable. The felo config set CLI command writes to ~/.felo/config.json which these scripts do NOT read — environment variable is the only supported method.
Linux/macOS:
CODEBLOCK0
For permanent configuration, add to your shell profile (~/.bashrc or ~/.zshrc):
CODEBLOCK1
Windows (PowerShell):
CODEBLOCK2
Windows (CMD):
CODEBLOCK3
3. Dependency: felo-livedoc
This skill depends on the felo-livedoc skill to obtain and create LiveDocs. Ensure felo-livedoc/scripts/run_livedoc.mjs is available at the same level as felo-superAgent/.
How to Execute
When this skill is triggered, follow these steps strictly in order. Execute all commands using the Bash tool.
Step 1: Check API Key
CODEBLOCK4
If not set, stop and show the user the setup instructions above.
Step 2: Obtain live_doc_id
This step ensures you always have a valid --live-doc-id before creating any conversation. (Note: live_doc_id corresponds to the API field live_doc_short_id.)
2a. If you already have a live_doc_id from ANY source in this session:
Skip to Step 3. Reuse the same ID. Sources include: a previous SuperAgent call's [state] output (the live_doc_short_id field), a felo-livedoc skill operation (create, list, etc.), user-provided input, or any other skill that returned a LiveDoc ID.
2b. If no live_doc_id is available from any source — fetch the LiveDoc list:
CODEBLOCK5
Parse the JSON output. The response contains data.items — an array of LiveDoc objects sorted by modification time descending. Find the first item where is_shared === false and use its short_id as your live_doc_id. NEVER pick an item where is_shared === true — shared LiveDocs belong to other projects and will cause a 502 error.
Example response:
CODEBLOCK6
Use: INLINECODE93
2c. If no is_shared === false item exists (or list is empty) — create one:
CODEBLOCK7
Parse the JSON output and extract data.short_id as your live_doc_id.
Example response:
CODEBLOCK8
2d. If the user explicitly requests a new canvas/workspace:
Create a new LiveDoc (same as 2c), then use the new ID for all subsequent calls. Discard the old live_doc_id.
Step 3: Determine Conversation Mode
Decide whether this is a new conversation or a follow-up:
| Condition | Mode | What to pass |
|---|
First question in session (no thread_short_id yet) | New conversation | INLINECODE99 only |
| User asks a follow-up / continues the topic (DEFAULT) |
Follow-up |
--thread-id AND
--live-doc-id |
| User explicitly says "new topic" / "change subject" | New conversation |
--live-doc-id only (same LiveDoc) |
| User's intent requires a
--skill-id not matching current thread | New conversation |
--live-doc-id +
--skill-id (same LiveDoc) |
| User explicitly says "new canvas" / "new LiveDoc" | New conversation | New
--live-doc-id from Step 2d |
IMPORTANT: The default for any user message after the first one is ALWAYS follow-up. Only treat it as a new conversation if the user explicitly requests it.
Step 4: Determine Skill ID (New Conversations Only)
If this is a new conversation (no --thread-id), analyze the user's intent:
Available skill IDs:
- -
twitter-writer — For composing, drafting, or posting tweets/X posts - INLINECODE109 — For creating logos, brand designs, or visual identity
- INLINECODE110 — For generating product images for e-commerce use
How to decide:
- 1. If the user explicitly specifies a skill-id, use that value
- Otherwise, analyze the user's request and determine if it matches one of the above
- If none match, do NOT pass INLINECODE111
If this is a follow-up (--thread-id is set), skip this step entirely. --skill-id is ignored in follow-up mode.
Step 4.5: Fetch and Select Brand Style (New Skill Conversations Only)
When to run this step: Only when this is a NEW conversation AND a skill ID was determined in Step 4 (twitter-writer, logo-and-branding, or ecommerce-product-image). Skip entirely for follow-up conversations or general (no skill) conversations.
Category mapping:
| Skill ID | Style category |
|---|
| INLINECODE117 | INLINECODE118 |
| INLINECODE119 |
IMAGE |
|
ecommerce-product-image |
IMAGE |
4.5a. If the user has already specified a style (by name, or by pasting a style block), use it directly — skip to 4.5d.
4.5b. Fetch the style list (names only):
IMPORTANT: Style DNA content is very large. Always use --json and extract only names/labels via Node.js to avoid Bash tool output truncation. Never call run_style_library.mjs without --json for listing purposes.
CODEBLOCK9
Replace en with the matching --accept-language value for the user's language (zh, ja, ko, en). Also update the .labels?.en reference in the node script to match (e.g. .labels?.zh for Chinese).
4.5c. Present the styles to the user and ask them to choose:
Output the COMPLETE list as plain text — every style returned, numbered sequentially. NEVER use the AskUserQuestion tool (it limits to 4 options and will silently drop styles). NEVER pre-select or filter styles on behalf of the user. Always append a "no preference" option last. Wait for the user's plain-text reply before proceeding.
Example output:
CODEBLOCK10
If the user picks "no preference" (0) or the list is empty, proceed to Step 5 without --ext.
4.5d. Build the --ext value:
Take the full text block for the chosen style (exactly as output by the script) and use it as the value of brand_style_requirement. The block may contain multiple lines — serialize them into a single JSON string with \n for newlines and \" for any double quotes inside field values:
Example style block output:
CODEBLOCK11
Serialized as --ext:
CODEBLOCK12
Important: Pass the brand_style_requirement value completely and verbatim — do NOT truncate Style DNA. Partial style content will degrade output quality.
Step 5: Run the Script
Construct and execute the command. ALWAYS use --json — in Claude Code's Bash tool, stdout is captured, not streamed to the user. JSON mode returns the full answer in a structured response.
IMPORTANT: The SSE stream may take a long time (especially for image generation, research reports, etc.). You MUST set the Bash tool timeout to at least 600000ms (10 minutes) when executing the script to prevent premature termination.
--accept-language selection: Default is en. Match the user's language — if the user writes in Chinese use zh, Japanese use ja, Korean use ko, etc.
--query construction: Do NOT simply pass the user's raw input as-is. You should enrich and refine the query to make it more complete and effective for SuperAgent:
- - Add context: If the conversation has prior context (e.g., the user previously discussed a topic), incorporate relevant details so SuperAgent understands the full picture.
- Clarify vague requests: If the user says something brief like "continue" or "go on", expand it to describe what should be continued (e.g., "Please continue the previous analysis and provide more details").
- Supplement missing details: If the user's request implies information they mentioned earlier (e.g., brand name, product type, style preference), include those details in the query.
- Preserve user intent: Never change the user's core intent. Only add context and clarity — do not inject opinions or redirect the topic.
- Keep it concise: The query has a 2000-character limit. Enrich the content but stay focused and avoid unnecessary padding.
Examples:
- - User says "continue" → INLINECODE150
- User says "one more" → INLINECODE151
- User says "fix it" → INLINECODE152
New conversation (first question, no skill):
CODEBLOCK13
New conversation with skill ID, no style selected:
CODEBLOCK14
New conversation with skill ID and brand style (from Step 4.5):
CODEBLOCK15
Follow-up question (DEFAULT for 2nd+ messages):
CODEBLOCK16
Step 6: Extract State and Output the Answer
After the script finishes, parse the JSON output:
CODEBLOCK17
- 1. Output
data.answer verbatim as your response text — print it exactly as-is so the user sees the full content. - Extract and save
data.thread_short_id and data.live_doc_short_id — you MUST use these in the next call. - Optionally show
data.live_doc_url so the user can view the LiveDoc canvas in a browser. - Image results (
data.image_urls): If this array is non-empty, append image links immediately after data.answer, formatted as one line per image:
CODEBLOCK18
Example output:
CODEBLOCK19
Each image has url (signed S3 URL, time-limited), title, and file_id (stable file identifier). Note: the same image may appear in both tools_result_stream and tools_result events with different signed URLs — deduplication is handled automatically by file_id. When referencing a previously generated image in a follow-up query, include its file_id in the --query so SuperAgent can locate the file (e.g., "Please generate a variation of file_id=b9e5be11-...").
Do NOT show thread_short_id or live_doc_short_id to the user unless they ask for it.
Complete Workflow Examples
Example A: Multi-turn Conversation (Most Common)
CODEBLOCK20
Step 2b: Fetch LiveDoc list → get live_doc_id = "QPetunwpGnkKuZHStP7gwt"
Step 3: First question → New conversation
Step 4: No special skill → no --skill-id
Step 5:
node felo-superAgent/scripts/run_superagent.mjs \
--query "What is quantum computing?" \
--live-doc-id "QPetunwpGnkKuZHStP7gwt" \
--accept-language en \
--json
Step 6: Parse JSON output. Output
data.answer verbatim as your response. Save
thread_short_id = "CmYpuGwBgCnrUdDx5ZtmxA",
live_doc_id = "QPetunwpGnkKuZHStP7gwt" from
data.
CODEBLOCK22
Step 2a: Already have live_doc_id → skip
Step 3: Follow-up (default) → use saved thread_short_id
Step 5:
node felo-superAgent/scripts/run_superagent.mjs \
--query "What are its practical applications?" \
--thread-id "CmYpuGwBgCnrUdDx5ZtmxA" \
--live-doc-id "QPetunwpGnkKuZHStP7gwt" \
--json
Step 6: Parse JSON output. Output
data.answer verbatim. Save updated
thread_short_id from
data (may be the same), keep
live_doc_id.
CODEBLOCK24
Step 3: Still follow-up (same topic) → use saved thread_short_id
Step 5: Same pattern as above with new query
Example B: Tweet Writing with Style Selection
CODEBLOCK25
Step 2a: Already have live_doc_id → reuse
Step 3: New conversation
Step 4: User intent matches "write a tweet" → --skill-id twitter-writer
Step 4.5: Fetch TWITTER styles (pass --accept-language matching user's language):
node felo-superAgent/scripts/run_style_library.mjs --category TWITTER --accept-language en
Output:
Style name: My Bold Voice
Style labels: bold, provocative
Style DNA: # My Bold Voice Style DNA
...(full content)
Style name: darioamodei
Style labels: Thoughtful long-form essays
Style DNA: # Dario Amodei (@DarioAmodei) Tweet Writing Style DNA
...(full content)
Present to user: "Which writing style would you like? 1. My Bold Voice (yours) 2. darioamodei (recommended) 3. No preference"
User selects: "1. My Bold Voice"
Step 5:
node felo-superAgent/scripts/run_superagent.mjs \
--query "Help me write a tweet about AI trends" \
--live-doc-id "QPetunwpGnkKuZHStP7gwt" \
--skill-id twitter-writer \
--ext '{"brand_style_requirement":"Style name: My Bold Voice\nStyle labels: bold, provocative\nStyle DNA: # My Bold Voice Style DNA\n...(full content)"}' \
--accept-language en \
--json
Step 6: Parse JSON output. Output
data.answer verbatim. Save new
thread_short_id from
data, keep same
live_doc_id.
CODEBLOCK29
Step 3: Follow-up → use saved thread_short_id (do NOT pass --ext again)
Step 5:
CODEBLOCK30
Example C: Logo Design with Style Selection
CODEBLOCK31
Step 4: Detected "design a logo" → --skill-id logo-and-branding
Step 4.5: Fetch IMAGE styles:
node felo-superAgent/scripts/run_style_library.mjs --category IMAGE --accept-language en
Output example:
Style name: Minimalist Modern
Style labels: clean, monochrome
Style DNA: ...(full content)
Cover file ID: file_333
Present styles to user and wait for selection. Suppose user picks "Minimalist Modern":
Step 5:
CODEBLOCK34
Example D: E-commerce Product Image with Style Selection
CODEBLOCK35
Step 4: Detected "product image" → --skill-id ecommerce-product-image
Step 4.5: Fetch IMAGE styles:
node felo-superAgent/scripts/run_style_library.mjs --category IMAGE --accept-language en
Present styles to user. Suppose user picks "No preference":
Step 5: (no --ext since user chose no preference)
CODEBLOCK37
Example E: User Requests a New Canvas
CODEBLOCK38
Step 2d: Create new LiveDoc:
node felo-livedoc/scripts/run_livedoc.mjs create --name "New Project" --json
Extract new
live_doc_id. Discard the old one. All subsequent calls use the new ID.
Example F: User Specifies Style Directly
CODEBLOCK40
Step 4: --skill-id twitter-writer
Step 4.5a: User already named the style → fetch the list to get the full block:
node felo-superAgent/scripts/run_style_library.mjs --category TWITTER --accept-language en
Find the entry with
Style name: darioamodei, extract its full block verbatim. No need to ask the user again.
Step 5:
CODEBLOCK42
Available Script Options
Core parameters:
- -
--query <text> (REQUIRED) — User question, 1-2000 characters - INLINECODE199 (REQUIRED for new conversations) — LiveDoc ID (
live_doc_id) to associate with - INLINECODE201 — Thread ID from previous response, for follow-up conversations
Skill parameters (new conversations only, ignored in follow-up):
- -
--skill-id <id> — Skill ID (see Constraint #9 for available skill IDs) - INLINECODE203 — Comma-separated resource IDs to include
- INLINECODE204 — Extra parameters as JSON object. For skill-based conversations, pass brand style as:
--ext '{"brand_style_requirement":"Style name: <name>\nStyle labels: <labels>\nStyle DNA: <full styleDna text>\nCover file ID: <id>"}'
Fields present depend on category type.
Cover file ID is omitted when null. Do NOT truncate
Style DNA.
Output control:
- -
--json / -j — Output JSON format with full metadata (ALWAYS use this in Claude Code — stdout is captured by the Bash tool, not streamed to the user) - INLINECODE210 /
-v — Log stream connection details to stderr (for debugging only, not needed for normal use) - INLINECODE212 — Language preference (e.g., en, ja, ko)
API Workflow (Reference)
The script handles this workflow automatically:
- 1. Create conversation:
- New:
POST /v2/conversations (requires
live_doc_short_id in body)
- Follow-up:
POST /v2/conversations/{threadId}/follow_up
- Returns:
stream_key,
thread_short_id, INLINECODE218
- 2. Consume SSE stream:
-
GET /v2/conversations/stream/{stream_key}
- Supports offset parameter for resuming:
?offset={lastOffset}
- Reconnects automatically if connection drops (2-second delay)
- 3. Parse events:
-
message — Direct text content
-
stream — Wrapped content with type information
-
heartbeat — Keep-alive signal
-
done /
completed /
complete — Stream finished
-
error — Error event (non-terminal, continues reading)
- 4. Extract tool results:
- Image generation (
generate_images)
- Research reports (
generate_discovery)
- Document generation (
generate_document)
- PPT generation (
generate_ppt)
- HTML generation (
generate_html)
- Twitter/X search (
search_x)
Base URL: https://openapi.felo.ai (override with FELO_API_BASE if needed).
Tool Support
SuperAgent may invoke tools during conversation. The script automatically extracts and displays:
Image Generation:
- - Tool: INLINECODE236
- Output: Image URLs and titles
Research & Discovery:
- - Tool: INLINECODE237
- Output: Research report titles and status
Document Generation:
- - Tool: INLINECODE238
- Output: Document titles and status
Presentation Generation:
- - Tool: INLINECODE239
- Output: PPT titles and status
HTML Generation:
- - Tool: INLINECODE240
- Output: HTML page titles and status
Twitter/X Search:
- - Tool: INLINECODE241
- Output: Tweet content, author info, metrics (likes, retweets, views)
Error Handling
Common Error Codes
| Code | HTTP | Description |
|---|
| INVALIDAPIKEY | 401 | API Key is invalid or has been revoked |
| SUPERAGENTCONVERSATIONCREATEFAILED |
502 | Failed to create conversation (upstream error) |
| SUPER
AGENTCONVERSATION
QUERYFAILED | 502 | Failed to query conversation details |
SSE Stream Errors
The stream may send:
- -
event: error with data: {"message": "..."} — treat as failure and show message - Connection timeout — script automatically reconnects with 2-second delay
- Idle timeout (2 hours) — stream aborted if no data received
Missing API Key
If FELO_API_KEY is not set, display this message:
CODEBLOCK43
Timeout Handling
- - The SSE stream has its own idle timeout: 2 hours (no data received). The stream stays open as long as data keeps flowing.
- Bash tool timeout: MUST be set to at least 600000ms (10 minutes) when executing the script, because the SSE stream can run for a long time.
Important Notes
- - Execute this skill immediately using the Bash tool — do not just describe what you would do
- ALWAYS use
--json — in Claude Code's Bash tool, stdout is captured, not streamed. JSON mode returns the answer in a structured response that Claude outputs as text - ALWAYS output
data.answer verbatim — print it exactly as-is as your response text so the user sees the full content - After create, the script connects to the stream immediately — the
stream_key has a limited validity period - Use the bundled Node script to consume SSE; do not assume
jq or other tools for parsing SSE - Same API key as other Felo skills (
FELO_API_KEY) - The script handles reconnection automatically if the stream drops
- Tool results are deduplicated to avoid showing the same resource multiple times
- If
live_doc_id is already known from any source (other skills, user input, previous calls), use it directly — do NOT fetch the LiveDoc list again - Multi-language support: Fully supports Simplified Chinese, Traditional Chinese, Japanese, and English
- The API returns results in the same language as the query when possible
Decision Flowchart
CODEBLOCK44
Style Library Script (run_style_library.mjs)
Fetch the style library list for a given category. Returns user styles first, then recommended styles.
CODEBLOCK45
Options:
- -
--category <category> (REQUIRED) — One of: TWITTER, INSTAGRAM, LEMON8, NOTECOM, WEBSITE, INLINECODE258 - INLINECODE259 — Language for labels/tags (e.g.
en, zh-Hans, ja). Default: en. Always pass this to match the user's language. - INLINECODE264 /
-j — Output raw JSON - INLINECODE266 — Request timeout (default 60)
Default text output format (one block per style, blank line between):
For TWITTER category:
CODEBLOCK46
Fields included per entry (fields with null/empty values are omitted):
- -
Style name — always present (name field) - INLINECODE269 — from
content.labels (TWITTER) or content.tags (other categories), in the requested language, comma-separated; omitted if not present - INLINECODE272 — from
content.styleDna (TWITTER type); omitted if not present - INLINECODE274 — from
coverFileId; omitted if null/empty
User-created styles appear before recommended styles.
References