QEDGE AMFR Copilot

Documentation

User manual

How the workspace fits together: chatting with your research, ingesting documents into the search layer, organizing private and group libraries alongside the shared corpus, and paying for usage with credits.

Getting started

Account & access

Sign in from the Chat page. New registrations must use an email on the admin allowlist, and you need to verify your inbox before you can use the workspace.

  • Standard users see Chat, Ingestion, Skills, Designer, Gallery, and Knowledge in the sidebar (private and group libraries).
  • Admins see the same workspace links plus an Admin section for billing, Shared corpus, Groups, inviting allowlisted users, and MCP servers.

For how data and research content are handled, see Privacy and Terms of use.

Preferences

Settings & models

Open Settings to manage your profile, API keys, and model preferences. The Models card is separate from profile fields — save each card with its own button.

Model preferences

Choose which Claude models power your research runs. Each dropdown offers three models —Claude Sonnet 5.5, Claude Opus 5.5, and Claude Haiku 5.5 — plus Workspace default to inherit the deployment baseline.

  • Agent model — Runs General Research Copilot and packaged agents (tool use, subagents, and research).
  • Composer model — Writes the final user-facing answer after the agent finishes its research phase.

When you pick a specific model, the card shows Anthropic list pricing per million tokens (input, cache writes, cache hits, and output). Your workspace may apply additional platform charges on top; see Credits & billing.

When settings take effect

  • Interactive chat — Applies to both General Research Copilot and packaged agents when you chat in the browser or via the Chat API on a thread. The next turn uses your saved agent and composer models. Changing the agent model starts a fresh agent session on that thread (the prior session fingerprint no longer matches). Changing only the composer model does not reset the agent session.
  • Scheduled tasks — Each schedule captures MCP, skills, and model choices when the task is created. Later runs use that frozen snapshot, not your live Settings. See Scheduled tasks.
  • Chat API — POST /copilot/api/ask has no per-request model fields. API runs use the models stored on your profile; update them with PATCH /auth/profile (see Chat API: models and profile).

Assistant

Chat & threads

The chat UI is built around threads — each thread keeps its own title, message history, and uploaded attachments.

  1. Use New chat to start a fresh thread. The first message you send (or file you attach) seeds the conversation.
  2. Search chats filters the thread list by titles and message content.
  3. Open a thread from the list; use Delete on a row to remove a thread when you no longer need it.
  4. Attach files in the composer to upload documents into the current thread before or while you ask questions. Uploads appear in the transcript for that thread.
  5. Submit with the Ask button, or press Ctrl+Enter (Windows/Linux) or ⌘+Enter (macOS) from the message box.
Knowledge scope. Use the Knowledge control in the composer to limit what indexed papers the assistant can retrieve: All accessible (default), Shared library, My library, or Selected groups (pick one or more group libraries). Standard users see public shared corpus papers, their own private uploads, and group libraries they belong to. Admins with All accessiblecan retrieve across the full workspace (including other users' private papers).

While the model works, you may see agent steps, tool activity, and downloadable artifacts (tables, plots, exports) tied to the assistant reply. Failed answers can be retried from the error state when available.

Concurrent threads and live runs

You can run several chats at the same time. Start a long answer in one thread, switch to another in the sidebar, and send a new question there — each thread keeps its own in-flight run on the server. Switching threads does not cancel the run you left behind.

  • One answer per thread — While a thread is working on a reply, the composer for that thread is disabled until the assistant message finishes (or fails). Start another question in a different thread if you want parallel work.
  • Live badge — Threads with an answer still in progress show a live label in the chat list so you can see which conversations are still running when you are looking at a different thread.
  • Background and resume — Runs continue on the server if you close the tab, refresh, or navigate elsewhere in the workspace. When you open that thread again, the UI reconnects to the in-flight message and streams any steps you missed, then keeps updating live until the answer completes.
  • Delete — You cannot delete a thread while it is live; wait for the run to finish or fail first.

Integrations

Connections

Connections links your personal accounts to Financial Research Copilot so you can pull files in, push chat output out, and wire packaged agents to external systems. Open the Connections panel from the Chat header (and from Ingestion when cloud import is available). Each link is per user — not shared across the workspace.

A connector shows Connected when your account is linked, Not connected when the server supports it but you have not signed in yet, or Unavailable when the workspace has not configured that provider (ask an admin to enable it on the backend).

  • Feishu Docs — OAuth sign-in. Use Send to… in the chat header to export the latest answer or the full thread as a Feishu document. On generated .md / .markdown artifacts, use Save to Feishu Docs.
  • Notion — OAuth sign-in. Same Send to… options for latest answer or full thread as a Notion page. Markdown artifacts can be saved to Notion from the Generated files list under an assistant reply.
  • Synology NAS — Sign in with your DSM URL, account, and password (and OTP if required).
    • Attach, ingest, and save — In chat, Attach → From Synology NAS adds a file from shared folders to the current thread. On Ingestion, From Synology NAS queues PDF / DOCX / XLSX / PPTX files or whole folders for indexing. Under an assistant reply, Save to… uploads generated artifacts to a folder you choose.
    • Synology MCP (General Research Copilot) — With NAS connected, include Synology in the composer Tools list (Auto or Manual). The run can list shares and folders, read documents on the NAS, mount larger files into the agent environment for analysis, write or upload outputs, and create folders — without downloading everything to your laptop first.
  • GitLab — Sign in with your GitLab host URL and a personal access token with api scope, then link a project and working branch you want the workspace to treat as your default repository.
    • GitLab MCP (General Research Copilot) — With GitLab connected and a project linked, include GitLab in the composer Tools list (Auto or Manual). The run uses MCP tools on that linked project: repository info, list paths, read text files, commit a file, create a branch, and open a merge request.
Connections vs MCP. Feishu and Notion are connection-only (send/save exports). GitLab and Synology are hybrid: Connections holds your account (and for GitLab, which repo/branch), while MCP & tools is how the General agent invokes them when you select those servers. Other MCP entries (Wind, Firecrawl, SEC EDGAR, custom URLs, etc.) are workspace services and do not use the Connections panel.
Tip: Switch the linked GitLab project in Connections when you move to a different repo; re-link the branch if your default integration branch changes. Disconnect any connector when you no longer want the workspace to use that account.

Integrations

MCP & tools

MCP (Model Context Protocol) connects the assistant to external tool servers your workspace exposes — data APIs, search, or custom backends. Admins register each server (name, URL, description, on/off) under Admin → MCP servers. Only servers marked enabled appear in chat.

In the chat composer, with the General Research Copilot agent (see Packaged agents), set Tools to:

  • Auto — the workspace picks relevant MCP servers from your question before the run (you’ll see a preview of the match while you type).
  • Manual — expand MCP servers and choose exactly which enabled servers to attach to the next message.

GitLab and Synology also appear in the Tools list when enabled, but they only activate for your user after the matching Connection is set up (GitLab also requires a linked project and branch). Selecting GitLab without a linked project, or Synology without a connected NAS, will not attach working MCP tools for that server. For GitLab, the backend injects your linked project path and branch into the prompt so the model knows which repository to use.

Packaged agents use a fixed data-source workflow (not the general MCP picker). The Tools control is locked to auto for those agents; use the General agent for full MCP auto/manual control, including optional GitLab and Synology when connected.

Reuse

Slash skills

Skills are reusable capabilities you invoke from chat with a slash id (for example /my_skill). Manage them from the Skills page; in the message box, type / to open suggestions for enabled skills.

  • Instruction skills — Free-form instructions the model follows when you trigger that skill. Any signed-in user can create and edit their own. Admins can set each skill’s visibility (for example public) so others in the workspace can reuse it; standard users' new instruction skills stay private.
  • Claude file skills — A slash alias mapped to a native Claude file-based skill: either an entry from Anthropic's catalog or a custom skill package (ZIP) uploaded for the workspace. Creating, editing, and catalog wiring is admin-only; everyone can use enabled aliases in chat once they exist.
Packaged agents (builtin or custom) do not use the general slash-skill workflow. Designer skills (custom/... packages with a SKILL.md and optional scripts) are different — they mount only on the custom agent that references them. Switch to General Research Copilot if you need slash instruction or file skills on a message.

Automation

Scheduled tasks

Use /schedule in a chat thread to run the same agent prompt on a recurring cadence. Schedules use your browser timezone and bill credits on each run like a normal chat turn.

  • /schedule every friday 9am Append latest flows to the dashboard
  • /schedule list — list tasks bound to this thread
  • /schedule stop task_abc123 — disable a task

Scheduled runs reuse the thread session when possible. The agent sees thread uploads, prior outputs, and your stored prompt each time and decides which files to continue from.

Frozen configuration. When you create a schedule, the platform snapshots your MCP mode, enabled MCP servers, slash skills, and agent/composer models at that moment. Subsequent runs keep that configuration even if you change Settings later. Create a new schedule to pick up new model or tool choices.

Agents

Packaged agents

The Agent control in the composer selects which research workflow backs the thread. General Research Copilot is the default: full knowledge scope and MCP tools in Auto or Manual mode, plus slash skills.

The other options are packaged agents: curated builtins plus any custom agents you published (or that were shared to you). Custom slugs look like custom/you/agent-name. Author them in Agent Designer; browse shared ones in the gallery.

Curated builtins include:

  • Compounder Identifier / v2 — Score whether a company can dominate, why, and for how long.
  • Fallen Angel Identifier — Point-in-time fallen-angel screen with factor scorecards and archive.

On those builtins the scoper records the issuer's query languages and local-script names. Web and broker-research search then run in each listed language, not English only, so a name whose home-market record is not in English is not treated as if that record were silent.

For packaged agents, the UI shows Preset MCP stack instead of the workspace MCP picker. Knowledge and manual MCP selection are disabled so the agent can follow its own retrieval and data rules.

After a packaged-agent turn, the research rail can show a short version label (a git SHA on builtins, or the publish release label / definition hash on custom agents). Custom labels are not git links.

If you later want follow-ups against ingested knowledge — changing Knowledge scope, using slash skills, or choosing MCP servers manually — switch the Agent control to General Research Copilot and continue in the same thread. Prior turns stay in the transcript so you do not need a new chat.

Custom agents

Agent Designer

Designer is a canvas for your packaged agents: an orchestrator plus specialist sub-agents, each with tools, MCP servers, and skills. The same definition Chat runs after you publish. Nothing on the canvas changes how a live turn executes until you save and publish.

Layout

  • Agent strip — Switch drafts, start New agent, or delete a chip. Names wrap on a narrow screen; delete is a small × (red on hover).
  • Library (left) — Searchable MCP servers, builtin tools (read, grep, glob, write, edit, bash), builtin skills, and your custom skills. Drag onto the orchestrator or a selected sub-agent.
  • Canvas — Graph of the orchestrator and sub-agents. Click a node to inspect it. Adding a sub-agent from the library creates a specialist role.
  • Inspector (right) — Name, system prompt, tools, MCP, and skills for the selected node.

Designer skills

Open Skills in the header. These are not slash skills. A Designer skill is a custom/... package: SKILL.md plus optional scripts (for example scripts/compute.py). Suggested slug: custom/you/skill-name. Visibility is private or public. Scripts ship into the agent sandbox; prompts should tell the specialist to run those scripts instead of re-deriving the math.

Agent output: charts and forms

Beyond Markdown, a published agent can return two kinds of rich block, both drawn by the chat UI. Each has a builtin skill that documents the exact payload, and both are prompt-level conventions rather than API calls: attach the skill in Skills so the agent has the spec, and the platform strips the raw block from the draft and renders the widget in its place.

  • Interactive charts — the builtin skill interactive-chart-blocks. The agent emits a fenced chart: block holding a small declarative JSON spec, and the answer renders a live chart (hover tooltips, legend, dual axes) instead of a static image or a Markdown table of the same numbers. Bar, line, area, composed, scatter and pie.
  • Input forms — the builtin skill interactive-form-gate. The agent emits an analyst_input_request block, and the answer renders a form the reader fills in; their typed answers come back to the agent as a table it parses. Used for confirm gates and any values only the reader has.

Two things to know when wiring either one up. The chart and form renderers live in the frontend, so an agent can emit these blocks before the frontend that draws them has shipped, in which case they show as plain code blocks. And a builtin skill resolves from the agents service's own skill directory, so the service must already carry the skill; attaching one that the deployment is missing fails the run rather than skipping the skill.

Save, validate, publish, share

  1. Save draft — Persists the definition. Drafts are only yours and are not runnable in Chat.
  2. Validate & publish — Checks MCP names, skills, and a full template build. Warnings are soft; hard errors block publish.
  3. Publish — Assigns a slug starting with custom/ (for example custom/you/test-agent-02) and freezes an immutable version. Optional release label (for example v1); if omitted, the definition hash is stored so Chat can show a version chip.
  4. Share (published only) — Private (you), Group, or Workspace (public). Workspace agents appear in the gallery. There is no open-web share: Gallery and Chat require a signed-in workspace account.
  5. Runs & earnings (published only) — Open Publish & earnings on the Designer toolbar. The package panel shows runs this month, lifetime runs, and Credits earned from other people running this slug.

Republishing keeps the slug and increments the version. Chat's Agent control lists published custom agents next to the builtins. On a packaged-agent turn you can press Debug at the right end of the composer toolbar (next to Send) to inspect coordinator and sub-agent input, output, files, and steps when the run used the agents VM or Claude (thread owner only). The toggle is stored per agent. General Research Copilot does not show Debug.

API. The same frc_ key can author agents at /copilot/designer/... and run a published slug with POST /copilot/api/ask. See API: Designer.

Data plane

Document & knowledge ingestion

There are several ways content enters the system — pick the one that matches your goal:

  • Chat attachments — Upload from the chat composer to work with files in a single thread. This is ideal for ad-hoc analysis alongside a conversation. The composer also accepts Markdown, JSON, and CSV for thread-only use; indexing into your knowledge libraries uses the ingestion formats below.
  • Ingestion → Local documents — On the Ingestion page, open the Local documents tab, choose one or more files, then queue ingestion. Supported formats are PDF (.pdf), Word (.docx), Excel (.xlsx), and PowerPoint (.pptx) — modern Office Open XML only, not legacy .doc / .xls / .ppt. Import from Synology via From Synology NAS after you connect your NAS; use the file-type filter when browsing folders to narrow the list. You must be signed in. Each file becomes its own run; use the Runs tab for live status and per-paper stats. Optional toggles include Dry run (parse without writing to the vector store) and Only ingest new papers (skip content already present). Use Sharing settings on the ingest form to target Private (only you), Group (members of selected knowledge groups), or Shared (workspace-wide shared corpus — admins only). Standard users can ingest to Private or Group for groups they belong to; they cannot publish to the shared corpus.
  • Ingestion → ArXiv discovery — On the same Ingestion page, open the ArXiv discovery tab to search arXiv, review candidates, and queue ingestion. Any signed-in user can use this workflow with the same sharing settings and optional toggles as local uploads.
  • Ingestion → Broker reports — On the Ingestion page, open the Broker reports tab to pull sell-side research for a company and its comparable peers. Enter a primary company (name or ticker), add comparable companies — or press Suggest comps to have the assistant propose a peer set you can edit — then choose your report sources (foreign brokers, domestic brokers, or both; domestic coverage is CICC, CITIC, CSC, and Huatai) and a date range (defaults to the last year). Each report is fetched, tagged with its publication date, and indexed for search and chat like any other document, with the same Sharing settings, Dry run, and Only ingest new papers options. Use the Runs tab for live status and per-report stats.
  • Ingestion → Stock pools (admins only) — A stock pool is a saved watchlist that re-ingests itself on a schedule, so a monthly coverage refresh does not have to be run by hand. Because a coverage list is usually hundreds of names, a pool is built by uploading a JSON file rather than adding companies one at a time. Pick a schedule (cron preset plus timezone) and a date window: Previous month (the month that just closed — the usual choice), Month to date, or a rolling Trailing days. On each run, Gangtise entries are discovered over that date range and NAS folders are filtered by the date in each filename; files whose filename carries no parseable date are never picked up. Pools are shared across admins — every admin sees and can edit every pool — and standard users never see the tab. Use Preview window to check which files a NAS folder would pick up before enabling a schedule, Run now for an immediate run that leaves the cron schedule untouched, and Pause to stop it firing — pausing only affects the schedule, so a run already in progress keeps going. Use Cancel run on the Runs tab summary to stop that one: names not yet started are dropped and the companies already ingesting finish. Names in a run are ingested concurrently on the same workers as ordinary uploads, so a few hundred stocks clear in a single pass rather than one at a time. A run uses at most half of the ingestion capacity, so uploads you submit while a pool is running start right away instead of waiting behind the whole watchlist. Every run creates ordinary ingestion jobs, so they appear in the Runs tab under a Stock pool runs summary that links to its child jobs. If a pool's owner later loses admin, the next run aborts and disables the pool rather than quietly ingesting to a different destination.
  • The watchlist file. Upload a JSON array of rows, or an object with an entries array alongside the pool's settings. A company row takes name — a bare string works as shorthand — plus optional code (the Gangtise gtsCode), scope (foreign, domestic, or both; blank inherits the pool's broker toggles, which the Target column shows as a dashed badge), and keywords (extra search terms when Gangtise has no exact security). Optional comparables (also comps / peers) lists peer companies ingested in the same broker job as that row — the same idea as comps on the Broker reports tab, not a second watchlist column type. A NAS row takes path and an optional file_type. Column names are forgiving (company, ticker, folder and similar all work) since the file usually comes out of a spreadsheet. On upload each row is checked and reported back: Resolved (matched a Gangtise security), Keyword (no exact match, so it will search the knowledge base by name instead), NAS folder, or Rejected. Rejected rows are skipped; the rest import.
  • Name vs code. The code is the Gangtise security identifier (600519.SH, TSM.N, 00700.HK) and it is what actually drives discovery; the name is a label. Lookups are a direct Gangtise search with no AI canonicalization, and only an exacthit on a ticker or on the security's own display name counts — so supply the name Gangtise itself shows (贵州茅台, not Kweichow Moutai), or the code. A near-miss is reported with the closest candidate so you can paste its code into the row. If a row carries both and they disagree, the code wins and the row is flagged as a Mismatch — nothing is mis-ingested, but the pool would otherwise show one company while ingesting another. Rows are relabelled with the canonical Gangtise name so the list stays consistent.
  • Companies Gangtise does not list. Some issuers have no security in Gangtise at all — PUMA and Adidas, for instance. Searching them does not fail cleanly: PUMA scores against Puma Biotechnology (PBYI.O) and Puma SE against 西南证券, both entirely different companies. That is why only exact matches become a code; everything else becomes a Keyword row that searches the knowledge base by name and never touches security resolution. Pool such names by leaving code out and listing every term worth searching under keywords — e.g. {"name": "Puma SE", "keywords": ["Puma SE", "PUMA", "Puma"]}, since the short ticker usually has better recall than the formal name and the results of both are combined.
  • NAS folders are the source for a period, not for a stock. A folder row ingests everyreport under that path whose filename date falls in the window — filenames are never matched against a company name. Point rows at folders that hold one desk's or one period's output, not at a shared archive. The folder path must match the NAS exactly, so use Browse NAS folder on an existing pool to copy a real path rather than typing one into the file.

Runs. The Runs tab lists your ingestion jobs with live status. Use the status tiles (queued / running / succeeded / failed) to narrow the list, and the search box to match titles, company names, filenames, or other job text. Clear filters restores the recent-runs view. Select a row for per-document summaries and errors.

SSRN PDFs. Upload a working paper you downloaded from SSRN through Ingestion → Local documents (or attach it from chat for a single thread). The pipeline recognizes common filenames such as ssrn-4098475.pdf. In chat, mention the paper in your question or use the rag knowledge-base tool to retrieve from ingested SSRN uploads.

Groups. Admins create groups and membership under Admin → Groups. A group gates both group knowledge libraries and threads shared with that group. Until you belong to at least one group, Group sharing is unavailable on ingest. Ask an admin to add you, or create a group if you have admin access.
Shared corpus. Publishing to the workspace-wide shared index (ingest Shared or maintaining Admin → Shared corpus) remains an admin responsibility. Standard users ingest to private or group libraries only.

Library

Knowledge libraries & access

Indexed research lives in one of three visibility tiers. Each tier controls who can retrieve a paper in chat and where it appears in the UI:

  • Private — Only you (and workspace admins) can search it. Listed under Knowledge → Private.
  • Group — Members of the assigned groups can search it. Listed under Knowledge → Groups. You can share the same document with multiple groups at ingest time.
  • Shared — Everyone in the workspace can search it. This is the shared corpus (public knowledge base). Browse it under Admin → Shared corpus (admins can also delete papers there).

The Knowledge page is for private and group libraries only — not the shared corpus. Use it to review what you have indexed, delete papers you own (or any paper if you are an admin), and change sharing on a paper (move between private, group, or shared) when you have permission. The shared-corpus browser uses the same search controls.

Keyword vs Semantic search. Library browsers offer a Keyword | Semantic toggle:

  • Keyword — Filter by source (arXiv, Document, YouTube), title words, and partial paper ID, then paginate. Broker reports and audio recordings are stored with source Document.
  • Semantic — Enter a natural-language query and press Search (results do not update while typing). The list returns the top matches by embedding similarity (not a paginated browse), with an optional source filter. Clear search returns you to the normal browse list while staying on the Semantic tab.
Tip: Match ingest sharing to how you want others to access a document, then use chat Knowledge scope — for example My library, Selected groups, or All accessible — so answers pull from the right libraries.
Admins. Create groups and manage membership under Admin → Groups. Maintain workspace-wide shared papers under Admin → Shared corpus. Admins can ingest or reclassify to Shared and read all tiers in chat when scope is All accessible.

Developers

API access

Mint a personal API key in Settings to call programmatic routes as your account. One key covers four route families:

  • Ingestion (/ingestion/...) — index documents into knowledge libraries.
  • Chat (/copilot/api/...) — ask questions, attach files, and collect answers plus output artifacts. Includes GET /copilot/api/agents (runnable slugs), POST /copilot/api/ask with a builtin or published custom/... agent_slug, and Sweeps (/copilot/api/sweeps) for batch runs across a portfolio.
  • Designer (/copilot/designer/...) — author skills, drafts, publish, share, and fork. Synchronous JSON (not jobs).
  • Account (/auth/...) — read and update profile fields, including agent and composer models used by chat runs.

API keys

  1. Open Settings → API keys → Create keywith a label (for example "Ingestion pipeline" or "Research bot").
  2. Copy the key immediately — the full value (starting with frc_) is shown only once.
  3. Revoke unused keys from the same page. Revoked keys return 401.
Tip: Treat a key like a password. Keys persist when the workspace uses a database; in local dev without one they reset on restart.

Authentication

Send the key on every request: Authorization: Bearer frc_.... The browser UI uses your session cookie instead — you do not need a key when using the web app.

Base URL

Programmatic routes are served by the backend API root, not the Next.js app shell. Build full URLs as:

https://your-domain/api + route path — for example https://frcopilot.qedgeam.com/api/copilot/api/ask.

  • /api is the FastAPI backend mount — always include it before route paths such as /ingestion/..., /copilot/api/..., or /auth/....

Curl examples below use the API_BASE placeholder for that backend root (for example https://frcopilot.qedgeam.com/api).

Agent skill download

Instead of wiring calls by hand, download a ready-made frcopilot-api skill that teaches your own AI agent tools — Cursor, Claude Code, Codex, and other SKILL.md-compatible agents — how to use this API. In Settings, open the Agent skill card and choose Download skill (.zip).

The archive holds SKILL.md (routes, examples, and job polling) and .authorization (your key and base URL). Unzip the frcopilot-apifolder into your tool's skills directory — for example .cursor/skills/ for Cursor or .claude/skills/ for Claude Code.

The bundle is generated per deployment, so its apiBasealways points at this workspace's API — the main service or a tenant's own domain. It ships with an empty apiKey: paste a key from API keys into .authorization, or press Download skill with this key in the one-time key dialog to pre-fill it.

Async jobs

Ingestion uploads and chat asks are job-based: the server returns 202 with a job_id, then you poll until status is succeeded or failed. Account routes such as /auth/profile respond synchronously.

  1. Submit the upload or ask request and record the job_id.
  2. Poll the ingestion or chat job endpoint until the job finishes.
  3. Read results from the final payload (ingest summaries, or chat answer + artifacts).

Job status values: queued → running → succeeded / failed. You only see your own jobs.

Ingestion API

Index documents into your knowledge libraries under /ingestion.

Endpoints

POST/ingestion/uploads

Body: raw document bytes (PDF, DOCX, XLSX, or PPTX). Headers: X-Filename and the document Content-Type. Query options: visibility, group_ids, dry_run, and only_new.

POST/ingestion/youtube

Body: JSON with urls (YouTube video or playlist URLs / IDs). Optional JSON fields: visibility, group_ids, dry_run, and only_new. No X-Filename header is needed.

POST/ingestion/audio

Body: raw audio bytes. Headers: X-Filename and the audio Content-Type. Query options: visibility, group_ids, dry_run, and only_new.

POST/ingestion/broker-reports

Body: JSON with primary (company name or ticker) and optional comparables, include_foreign, include_domestic, domestic_brokers (subset of CICC, CITIC, CSC, Huatai), date_from, date_to, and limit. Query options: visibility, group_ids, dry_run, and only_new. Requires broker-research credentials to be configured (otherwise returns 503).

POST/ingestion/broker-reports/suggest-comps

Body: JSON with primary. Returns a suggested, editable set of comparable companies (name + code) to feed into /ingestion/broker-reports.

GET/POST/ingestion/pools · /ingestion/pools/{pool_id}

Admins only (standard keys get 403). Manage scheduled stock pools. Create body: name, cron_expr, timezone, window_mode (previous_month / current_month / trailing_days), trailing_days, the ingest defaults (visibility, group_ids, dry_run, only_new, include_foreign, include_domestic, domestic_brokers, limit — max reports per Gangtise company job; NAS folders ignore it), and an optional entries array. PATCH updates any of those; DELETE removes the pool and its runs.

POST/ingestion/pools/import

Create a whole pool from a JSON watchlist — the practical way to load hundreds of names. Body: the pool settings plus an entries array (a bare array is also accepted, and creates a pool with default settings). Company rows take name (a bare string works), optional code, scope (foreign / domestic / both, blank inherits the pool default), keywords, and optional comparables (peer companies for the same broker job); NAS rows take path and optional file_type. Names are resolved directly against Gangtise, falling back to a keyword search on a miss. The response reports every row's outcome (code, keyword, folder, error); rejected rows are skipped rather than failing the import. Add ?dry_run=true to get the report without creating anything. Use POST /ingestion/pools/{pool_id}/entries/import (with ?replace=true to swap the list wholesale) to load the same file into an existing pool.

POST/ingestion/pools/{pool_id}/entries

Add one target to a pool. Body: kind (gangtise_code / gangtise_keyword / synology_folder) plus code, keyword + keywords, or synology_path + synology_file_type. Optional scope (foreign / domestic / both) overrides the pool broker toggles for this row, and comparable_refs ingests peer companies alongside the primary. PATCH / DELETE on /entries/{entry_id}.

POST/ingestion/pools/{pool_id}/run · GET/runs · /preview

POST /run queues an immediate run (202 with a run_id) without moving the cron schedule, and returns 422 if the pool has no enabled entries. GET /runs returns run history including the child job_ids to poll via /ingestion/jobs/{job_id}. GET /preview resolves the current window and lists the NAS files each folder entry would match, with no writes. POST /runs/{run_id}/cancel stops a queued or running run (409 once it is terminal): names not yet started are dropped and companies already ingesting finish. Pausing a pool (PATCH enabled: false) only stops the schedule — it never cancels a run.

GET/ingestion/jobs

List recent jobs. Optional query: limit (1–100), q (case-insensitive match on query text, kind, owner, or result titles), status (queued / running / succeeded / failed), and kind (ingestion job kind). Standard users only see their own jobs.

GET/ingestion/jobs/{job_id}

Poll for status and per-document ingest summaries.

GET/ingestion/corpus/papers · /ingestion/my-corpus/papers · /ingestion/group-corpus/papers

Paginated keyword browse for the shared corpus, your private library, or group libraries. Optional filters: source, title, paper_id, abstract, doi, limit, offset. Group listing also accepts group_ids (comma-separated).

POST/ingestion/corpus/papers/search · /ingestion/my-corpus/papers/search · /ingestion/group-corpus/papers/search

Semantic (embedding) search within the same scopes. JSON body: query (required), optional source, limit (default 40, max 100). Group search may include group_ids. Returns top papers by similarity with optional score and match_excerpt — not offset-paginated.

Parameters by endpoint

  • /ingestion/uploads — raw document body; X-Filename header; optional query parameters visibility, group_ids, dry_run, and only_new.
  • /ingestion/youtube — JSON body with required urls; optional JSON fields visibility, group_ids, dry_run, and only_new.
  • /ingestion/audio — raw audio body; X-Filename header; optional query parameters visibility, group_ids, dry_run, and only_new.
  • /ingestion/broker-reports — JSON body with required primary and optional comparables, include_foreign, include_domestic, domestic_brokers, date_from, date_to, and limit; optional query parameters visibility, group_ids, dry_run, and only_new.
  • /ingestion/jobs — optional limit, q, status, and kind.
  • Corpus /papers (GET) — keyword filters and pagination; /papers/search (POST) — semantic query + optional source / limit (and group_ids for group corpus).
  • visibility accepts private, group, or public. Omit it to get your role’s default — the shared corpus for admins, your private library for everyone else (see visibility below).
  • group_ids is required when visibility=group. For raw upload/audio endpoints it is comma-separated in the query string; for YouTube it is a JSON list in the request body.

Visibility (where documents land)

Maps to the same tiers as the UI (see Knowledge libraries & access):

  • Private (visibility=private) — only you (and admins).
  • Group (visibility=group + group_ids) — members of those groups. Standard users must belong to each group or get 403.
  • Shared (visibility=public) — workspace corpus. Admins only; a standard-user key asking for it gets 403.
Mind the default. Omitting visibilitymeans “use my role’s default”: an admin key publishes to the shared corpus, a standard-user key lands in private. Naming a destination you may not write to is an error rather than a silent redirect, so a standard-user key that passes visibility=public gets 403 and nothing is ingested. Pass visibility explicitly whenever the destination matters.

Batch uploads

You can submit many uploads concurrently, but the backend processes with limited concurrency. Collect each job_id, then poll — do not assume immediate parallel completion. Re-uploading identical content is safe (de-duplicated).

Poll responsibly: space checks 5-10 seconds apart and back off when many jobs are still pending. For large batches, sweep with GET /ingestion/jobs?limit=N once per cycle instead of hitting /ingestion/jobs/{job_id} for every outstanding job. A job stuck in queued with nothing running for a long time is likely orphaned — resubmit it rather than polling indefinitely.

Example — private upload

curl -X POST "{{API_BASE}}/ingestion/uploads?visibility=private" \
  -H "Authorization: Bearer frc_..." \
  -H "X-Filename: report.pdf" \
  --data-binary @report.pdf

Example — poll job

curl "{{API_BASE}}/ingestion/jobs/JOB_ID" \
  -H "Authorization: Bearer frc_..."

Example — semantic search (private library)

curl -X POST "{{API_BASE}}/ingestion/my-corpus/papers/search" \
  -H "Authorization: Bearer frc_..." \
  -H "Content-Type: application/json" \
  -d '{"query":"gold mining cost curve","source":"upload","limit":20}'

Chat API

Run headless chat under /copilot/api. API chats are real threads owned by your account — they appear in the browser Chat list. Reusing a thread_id restores the agent session and any files attached to the thread.

Models and profile

Chat runs resolve agent and composer models from your stored profile — POST /copilot/api/ask has no per-request model fields. Update models before asking, or rely on what you saved in Settings (see also Settings & models):

Account endpoints

GET/auth/model-presets

List selectable agent and composer models, workspace defaults, and Anthropic list pricing per model.

PATCH/auth/profile

Update profile fields. Set agent_model and/or compose_model to a preset id (e.g. claude-sonnet-5-5) or null to revert to workspace default.

Example — set models for subsequent chat jobs

curl -X PATCH "{{API_BASE}}/auth/profile" \
  -H "Authorization: Bearer frc_..." \
  -H "Content-Type: application/json" \
  -d '{"agent_model": "claude-opus-5-5", "compose_model": "claude-sonnet-5-5"}'

Chat endpoints

POST/copilot/api/threads

Create a thread (optional title). Use before attaching files.

POST/copilot/api/threads/{thread_id}/uploads

Attach a file (raw body + X-Filename). Recorded on the thread; auto-attaches on every later turn.

GET/copilot/api/threads/{thread_id}

Thread sharing state, pasteable share_url, and latest_job (same poll object as /jobs/{job_id}).

PATCH/copilot/api/threads/{thread_id}/sharing

Share the thread. Body: visibility (private / group / public / internet) and group_ids when visibility=group. Returns share_url.

DELETE/copilot/api/threads/{thread_id}

Soft-archive the thread (same as the browser Chat delete). Returns 204. The row stays; it leaves the sidebar. 404 if missing, already archived, or not yours.

GET/copilot/api/skills

List slash skills visible to your account (skill_id, name, kind, enabled). Optional query: q to filter.

GET/copilot/api/agents

List packaged agents you may run via agent_slug: builtins plus your published custom agents and workspace-gallery agents (public). Optional query: q to filter. This is the run catalog — authoring lives under /copilot/designer.

POST/copilot/api/ask

Ask a question. Body: question (required; may include /skill_id tokens), thread_id, title, then optionally agent_slug, mcp_mode, mcp_servers, knowledge_scope.

GET/copilot/api/jobs/{job_id}

Poll for answer and artifacts[] (each with download_url) when succeeded.

POST/copilot/api/jobs/{job_id}/cancel

Cancel a queued or running job. Queued jobs become cancelled immediately. Running jobs become cancelling while the agent is interrupted and the run drains to idle; then the job and message are cancelled. Idempotent — a no-op on jobs that already finished.

GET/copilot/api/jobs

List your recent chat jobs. Optional thread_id filters to one thread.

GET/copilot/api/jobs/{job_id}/artifacts/{file_id}/download

Download an output artifact. Add ?inline=true to view inline.

Scheduled tasks (API)

The API-key counterparts of the browser /schedule command. Tasks are bound to a thread and freeze MCP servers, skills, and models at creation time, so recreate a task after republishing an agent.

Scheduled task endpoints

POST/copilot/api/threads/{thread_id}/schedules

Create a schedule. Body: prompt plus exactly one of cron_expr (standard 5-field cron, skips the phrase parser) or schedule_text (e.g. every friday 9am). Optional timezone (IANA, also accepted as client_timezone), human_summary, agent_slug, mcp_mode, mcp_servers, knowledge_scope.

GET/copilot/api/threads/{thread_id}/schedules

Schedules bound to one thread.

GET/copilot/api/schedules

All your schedules. Each task includes thread_title, the name of the thread it runs in.

PATCH/copilot/api/schedules/{task_id}

Body: enabled (pause or resume).

DELETE/copilot/api/schedules/{task_id}

Delete the task.

POST/copilot/api/schedules/{task_id}/run

Fire immediately without moving the cron. Returns as soon as the run is dispatched; 402 when the account has no credit, 409 when a run is already in progress.

GET/copilot/api/schedules/{task_id}/runs

Run history, newest first, each with status, error, answer, and artifact_file_ids.

Scheduled runs are not chat jobs, so they do not appear under /copilot/api/jobs; read the answer from the runs list. Each fire prepends [Scheduled run — task <id> — <ISO timestamp> — run <n>] to the prompt, so a recurring task can read its own as-of date from the envelope.

Agent, MCP, and knowledge scope

Optional POST /copilot/api/ask fields (same semantics as the browser composer). Order below reflects how you typically set them:

  1. agent_slug — packaged agent. Builtin example: compounder-identifier-v2. Custom (published Designer) example: custom/you/test-agent-02. Omit for General Research Copilot. Packaged agents (builtin or custom/...) use a fixed MCP allowlist; mcp_mode / mcp_servers and slash skills are ignored. Drafts are not runnable. Unknown custom slugs fail on poll, not at submit. Use GET /copilot/api/agents to discover slugs.
  2. mcp_mode + mcp_servers — mcp_mode: "auto" (default) lets the router pick enabled servers from your question; mcp_mode: "manual" attaches the slugs you list (lowercase), e.g. edgar-13f, rag, firecrawl, yfinance, gitlab.
  3. knowledge_scope — which knowledge libraries the RAG MCP may search when rag is attached (auto or manual). Defaults to "all". Has no effect unless RAG is in the MCP set. Mirrors the composer Knowledge control (see Chat & threads).

Accepted knowledge_scope values:

  • "all" — all tiers your account can access (shared, private, and your groups; admins see more).
  • "public" — shared corpus only.
  • "private" — your private library only.
  • JSON string for selected groups (see example below). Optionally add "public": true and/or "private": true to mix tiers with specific groups.

Example — group-scoped knowledge_scope value

{"mode":"custom","group_ids":["GROUP_ID"]}

Example — EDGAR 13F MCP

curl -X POST "{{API_BASE}}/copilot/api/ask" \
  -H "Authorization: Bearer frc_..." \
  -H "Content-Type: application/json" \
  -d '{
    "question": "Show Bill Ackman MSFT holdings in Q1 2026",
    "mcp_mode": "manual",
    "mcp_servers": ["edgar-13f"]
  }'

Example — RAG MCP with shared corpus only

curl -X POST "{{API_BASE}}/copilot/api/ask" \
  -H "Authorization: Bearer frc_..." \
  -H "Content-Type: application/json" \
  -d '{
    "question": "What do broker reports say about MSFT?",
    "mcp_mode": "manual",
    "mcp_servers": ["rag"],
    "knowledge_scope": "public"
  }'

Example — published custom agent

curl "{{API_BASE}}/copilot/api/agents?q=test-agent" \
  -H "Authorization: Bearer frc_..."
curl -X POST "{{API_BASE}}/copilot/api/ask" \
  -H "Authorization: Bearer frc_..." \
  -H "Content-Type: application/json" \
  -d '{
    "question": "AAPL 1y daily return, vol, Sharpe, max drawdown",
    "agent_slug": "custom/you/test-agent-02"
  }'

Slash skills

The chat API supports the same slash skills as the browser composer. There is no separate skill_ids field — prefix question with /skill_id (must be followed by whitespace or end of string). Use GET /copilot/api/skills to discover ids your API key can invoke.

  • Instruction skills — inject custom instructions for that turn.
  • Claude file skills — workspace file-based / native catalog skills.
  • Packaged agent_slug values ignore slash skills (same as the UI).
  • Unknown or disabled skills fail the background job — poll error on the job (validation runs after 202, not at submit time).

Example — list skills, then invoke one

curl "{{API_BASE}}/copilot/api/skills" \
  -H "Authorization: Bearer frc_..."

curl -X POST "{{API_BASE}}/copilot/api/ask" \
  -H "Authorization: Bearer frc_..." \
  -H "Content-Type: application/json" \
  -d '{"question": "/summarize What changed in the latest CPI print?"}'

Thread status, sharing, and delete

After POST /copilot/api/ask, poll the run until it finishes, then optionally share the thread and copy a pasteable link into a note or doc. This is the same Share hub as the browser Chat page. Delete is the same soft-archive as the Chat sidebar.

  • Job status — GET /copilot/api/jobs/{job_id} returns queued / running / cancelling / succeeded / failed / cancelled, plus answer and artifacts when done. Cancel an in-flight job with POST /copilot/api/jobs/{job_id}/cancel. GET /copilot/api/jobs?thread_id=... lists jobs on one thread.
  • Thread status — GET /copilot/api/threads/{thread_id} returns sharing fields and latest_job (same object as job poll) when you have a thread_id but not the job_id.
  • Share — PATCH /copilot/api/threads/{thread_id}/sharing with visibility and, for groups, group_ids. The response share_url is the link to put in a document.
  • Delete — DELETE /copilot/api/threads/{thread_id} soft-archives the thread (204, empty body). Same as the browser Chat delete: the row stays, it leaves the sidebar, and local attachment copies are dropped. 404 if the thread is missing, already archived, or not yours. Public/shared links stop resolving once archived.

Accepted visibility values (thread sharing, not ingest):

  • private — owner only. share_url is null.
  • group — members of group_ids (you must belong, unless admin). Link is /chat/shared/{thread_id} (sign-in required).
  • public — whole workspace ("shared"). Same signed-in /chat/shared/{thread_id} link.
  • internet — anyone with the link, no sign-in. Mints a revocable public_share_slug and returns /chat/public/{slug}. Switching away from internet clears the slug and kills the public link.

Example — poll until the thread run finishes

curl "{{API_BASE}}/copilot/api/jobs/JOB_ID" \
  -H "Authorization: Bearer frc_..."

curl "{{API_BASE}}/copilot/api/threads/THREAD_ID" \
  -H "Authorization: Bearer frc_..."

Example — share to the workspace (signed-in link)

curl -X PATCH "{{API_BASE}}/copilot/api/threads/THREAD_ID/sharing" \
  -H "Authorization: Bearer frc_..." \
  -H "Content-Type: application/json" \
  -d '{"visibility": "public"}'

Example — share to selected groups

curl -X PATCH "{{API_BASE}}/copilot/api/threads/THREAD_ID/sharing" \
  -H "Authorization: Bearer frc_..." \
  -H "Content-Type: application/json" \
  -d '{"visibility": "group", "group_ids": ["GROUP_ID"]}'

Typical workflow

  1. Discover (optional) — GET /copilot/api/skills for slash ids; GET /copilot/api/agents for runnable agent_slug values (builtin + published custom).
  2. Create a thread (optional) — skip for one-shot questions; ask creates a thread automatically.
  3. Attach files to the thread (optional), one upload per file.
  4. Ask with thread_id — thread attachments are picked up automatically.
  5. Poll until succeeded, then read answer and artifacts. GET /copilot/api/threads/{thread_id} also exposes the same job as latest_job.
  6. Download artifacts from each download_url.
  7. Share (optional) — PATCH /copilot/api/threads/{thread_id}/sharing and copy share_url into a doc. public is the whole workspace; internet is anyone with the link; group needs group_ids.
  8. Delete (optional) — DELETE /copilot/api/threads/{thread_id} soft-archives the thread (same as the browser Chat delete).

Example — one-shot ask

curl -X POST "{{API_BASE}}/copilot/api/ask" \
  -H "Authorization: Bearer frc_..." \
  -H "Content-Type: application/json" \
  -d '{"question": "Summarize the latest CPI print"}'

Example — poll chat job

curl "{{API_BASE}}/copilot/api/jobs/JOB_ID" \
  -H "Authorization: Bearer frc_..."

Example — cancel a running chat job

curl -X POST "{{API_BASE}}/copilot/api/jobs/JOB_ID/cancel" \
  -H "Authorization: Bearer frc_..."

Example — share a finished thread and copy the link

curl -X PATCH "{{API_BASE}}/copilot/api/threads/THREAD_ID/sharing" \
  -H "Authorization: Bearer frc_..." \
  -H "Content-Type: application/json" \
  -d '{"visibility": "internet"}'

Example — delete (soft-archive) a thread

curl -X DELETE "{{API_BASE}}/copilot/api/threads/THREAD_ID" \
  -H "Authorization: Bearer frc_..."
Threads & sessions. Pass the same thread_id on later asks to continue the conversation. UI and API turns on the same thread share one agent session.
Tip: Chat jobs bill credits like a normal turn. A failed job may mean insufficient balance — check error on the job.

Sweeps API

A sweep is a saved matrix of ordinary chat runs. Every ticker × as-of date × stage becomes one run, and each run is submitted as a new thread and a normal chat turn — so billing, Debug, artifacts, and sharing work per row with no separate execution path. Routes live under /copilot/api/sweeps and are synchronous JSON: the create call returns immediately, then a background worker drives the rows.

Stages run in order per ticker/date. Stage 2 is submitted only after stage 1 succeeded; when a stage fails permanently or is cancelled, the stages behind it become skipped. The worker submits at most one run per minute per sweep and pauses submitting while the queue is backed up, so a large sweep is a slow batch rather than a burst of chats. A sweep is capped at 2000 runs.

Sweep endpoints

POST/copilot/api/sweeps

Create a sweep and expand it into run rows. Returns 201 with sweep and total_runs.

GET/copilot/api/sweeps

List your sweeps (limit 1–200, default 50) with per-status counts.

GET/copilot/api/sweeps/{sweep_id}

One sweep: status, spec, attempt/timeout settings, counts, and timestamps.

GET/copilot/api/sweeps/{sweep_id}/runs

The run table. Optional filters status, ticker, and stage_index (0-based).

PATCH/copilot/api/sweeps/{sweep_id}

{"status": "paused" | "running"} — stop or resume submission. In-flight runs keep going; 409 once the sweep is terminal.

POST/copilot/api/sweeps/{sweep_id}/cancel

Cancel the sweep and every queued/running child job. Cancelled rows stay cancelled.

POST/copilot/api/sweeps/{sweep_id}/retry-failed

Reset exhausted failures to pending with attempt=0, and reopen the stages that were skipped behind them.

GET/copilot/api/sweeps/{sweep_id}/export.csv

Download the run table as CSV, including score columns and thread_id / job_id.

DELETE/copilot/api/sweeps/{sweep_id}

Remove the sweep from your list. Add ?archive_threads=true to also archive the chat threads its runs created. Run history, CSV, and billing are kept; 409 while the sweep is still running or paused.

Create body: name (required), stages (1–10, in execution order), and a portfolio. A ticker needs a date from either as_of_dates (shared) or portfolio[].as_of (per ticker). Use tickers for bare symbols, or portfolio for {"ticker", "name", "as_of"} rows. Optional: save_to_synology, max_attempts (1–10, default from the deployment), run_timeout_seconds (60–86400).

Each stage is {"agent_slug", "label", "prompt", "save_to_synology"}.agent_slug is any packaged assessment agent or a published custom/.... The general assistant is chat-only — it has no assessment workflow, so the API rejects it with 400 and the picker does not offer it. A stage prompt is an optional template; placeholders are {ticker}, {name}, {as_of}, {stage_label}, {stage_index} (1-based), {sweep_name}, and {attempt}. The platform always appends a short unattended sentence (auto-approve every gate, finish the run) and the Synology save instruction when enabled. It never describes an agent's output — a scorecard, a memo, or anything else — because the agent already defines that.

Deleting. DELETE is a soft delete: the sweep leaves your list and the API, while the run rows stay for export, audit, and billing. Chat threads are real work, so they are only archived when you ask for it with ?archive_threads=true — and that is the same soft archive as deleting a thread in Chat (it leaves the sidebar; share links stop resolving). Threads you already deleted are skipped and reported as threads_already_gone, so a partly tidied sweep still deletes cleanly. The response carries status: "deleted" plus threads_total, threads_archived, and threads_already_gone. Cancel a running sweep first (409 otherwise).

Sweep status: running | paused | succeeded | failed | cancelled. Run status: pending → submitting → queued → running → succeeded | failed | skipped | cancelled. attempt counts submissions (retries get a fresh thread). score is populated only for agents with a known scorecard and carries composite, coverage, coverage_met, and source (artifact or answer); agents without one leave it empty.

Example — create, watch, steer, export

# 2 tickers x 1 date x 2 ordered stages = 4 runs
curl -X POST "{{API_BASE}}/copilot/api/sweeps" \
  -H "Authorization: Bearer frc_..." \
  -H "Content-Type: application/json" \
  -d '{
        "name": "China quality - 2025 year-end",
        "as_of_dates": ["2025-12-31"],
        "tickers": ["600519.SH", "0700.HK"],
        "stages": [
          {"agent_slug": "compounder-identifier-v2", "label": "Compounder v2"},
          {"agent_slug": "fallen-angel-identifier", "label": "Fallen Angel"}
        ],
        "save_to_synology": true,
        "max_attempts": 2
      }'

curl "{{API_BASE}}/copilot/api/sweeps/SWEEP_ID" \
  -H "Authorization: Bearer frc_..."
curl "{{API_BASE}}/copilot/api/sweeps/SWEEP_ID/runs?status=failed" \
  -H "Authorization: Bearer frc_..."

curl -X PATCH "{{API_BASE}}/copilot/api/sweeps/SWEEP_ID" \
  -H "Authorization: Bearer frc_..." -H "Content-Type: application/json" \
  -d '{"status":"paused"}'

curl -X POST "{{API_BASE}}/copilot/api/sweeps/SWEEP_ID/retry-failed" \
  -H "Authorization: Bearer frc_..."
curl -X POST "{{API_BASE}}/copilot/api/sweeps/SWEEP_ID/cancel" \
  -H "Authorization: Bearer frc_..."

curl "{{API_BASE}}/copilot/api/sweeps/SWEEP_ID/export.csv" \
  -H "Authorization: Bearer frc_..." -o sweep.csv
Tip: Poll the sweep every 15–60s rather than each run. A run carries its own thread_id and job_id, so anything the chat routes expose (answer, artifacts, sharing) applies to that one run.

Designer API

Author custom packaged agents with the same frc_ key. Routes are synchronous JSON (not jobs). Drafts appear in Designer; only a published slug is runnable on POST /copilot/api/ask. Skill slugs and publish slugs must start with custom/ (suggested custom/you/name). See Agent Designer for the browser flow.

Designer endpoints

GET/copilot/designer/palette

MCP servers, builtin tools, and skills you can attach on the canvas.

POST/copilot/designer/skills

Create a Designer skill. Body: slug, markdown (SKILL.md, max 12k), visibility (private / public), optional scripts[] (path + content, 200k each).

GET PUT DELETE/copilot/designer/skills

List skills; GET / PUT / DELETE /copilot/designer/skills/{id} for one skill.

POST/copilot/designer/agents

Create a draft. Body: display_name and definition (orchestrator system, mcp_allowlist, tools, skills, subagents[]). Builtin tools only: read, grep, glob, write, edit, bash. Sub-agent mcp_names are unioned into the allowlist on save.

GET PUT DELETE/copilot/designer/agents

List your drafts; /copilot/designer/agents/{id} for one agent.

POST/copilot/designer/agents/{id}/validate

Soft warnings in the JSON body; hard errors return 400.

POST/copilot/designer/agents/{id}/publish

Freeze a version. Body: slug (must start with custom/) and optional release_commit (label; defaults to the definition hash). Republish keeps the slug and increments version. 409 if another package already owns that slug.

POST/copilot/designer/agents/{id}/share

Published only. Body: visibility (private / group / public) and group_ids when visibility=group. internet is stored as Workspace.

POST/copilot/designer/agents/{id}/fork

Copy a shared published agent into a new draft you own.

GET/copilot/designer/gallery

Workspace-shared published agents (same list as Gallery). Optional query: q, sort=trending|recent|useful (default trending).

Example — create skill, draft, validate, publish

curl -X POST "{{API_BASE}}/copilot/designer/skills" \
  -H "Authorization: Bearer frc_..." \
  -H "Content-Type: application/json" \
  -d '{"slug":"custom/you/equity-stats","markdown":"# Equity stats\n","visibility":"private","scripts":[]}'
AGENT_ID=$(curl -sS -X POST "{{API_BASE}}/copilot/designer/agents" \
  -H "Authorization: Bearer frc_..." \
  -H "Content-Type: application/json" \
  -d @definition.json | python3 -c "import sys,json; print(json.load(sys.stdin)['id'])")
curl -X POST "{{API_BASE}}/copilot/designer/agents/$AGENT_ID/validate" \
  -H "Authorization: Bearer frc_..."
curl -X POST "{{API_BASE}}/copilot/designer/agents/$AGENT_ID/publish" \
  -H "Authorization: Bearer frc_..." \
  -H "Content-Type: application/json" \
  -d '{"slug":"custom/you/test-agent-02","release_commit":"v1"}'
Do not POST create under /copilot/api/agents — that path is the run catalog. Author at /copilot/designer/..., then run the published slug with POST /copilot/api/ask.

Billing

Credits & billing

Financial Research Copilot uses a prepaid credit balance. Each assistant turn can debit your account after usage is metered; you’ll see notices in the chat sidebar when a charge completes, when metering is still pending, or when a run failed (including insufficient balance).

  • View balance — Open the chat sidebar and expand Available balance. Recent ledger lines (purchases, grants, Agent share credits, and chat debits) appear below when history exists. Filter Credits in for added credits (purchases, top-ups, and Agent share);Chat usage for debits.
  • Agent share— When someone else runs your published custom agent, you receive half of that turn's platform markup as a credit (shown as Agent share). Fractions under one cent wait until they add up. Running your own agent does not pay you. Track runs and credits on the published package in Designer under Publish & earnings.
  • Buy credits — With Stripe enabled on the API, preset amounts appear under Buy credits. Choosing one starts a secure checkout; after payment, your balance updates when Stripe confirms (usually within a few seconds). Return URLs may show a short billing status message.
  • Admin grants — Organization admins can credit an account from Admin → Billing for promos, manual payments, or adjustments. Those entries show up in the user’s history like any other top-up.

How charges are calculated. The expanded balance panel explains that consumption reflects platform AI processing pricing — underlying model usage, tax recovery, infrastructure, and margin — rather than a flat per-message fee. Admins can open a usage request’s detail drawer to compare base cost, tax recovery, markup, and per-component token metering for auditing.

Layout

Mobile & narrow screens

On small viewports, the chat sidebar becomes a slide-out drawer: use the menu control in the header to open threads, billing, workspace links, and sign out. The billing panel can expand to focus on balance and purchase controls. Workspace pages wrapped in the shell use the same pattern.

Tables (for example on Knowledge) scroll horizontally when needed so columns stay readable without cramping the layout.