@flowapt/flowiq-cli
v0.1.11
Published
Command-line tool for FlowIQ staff: round-trip agent prompts, questionnaires, fine-tuning, pin-board tasks, webhooks, templates, agent-updates, chat exports, and live agent testing without ever touching service-role credentials.
Maintainers
Readme
flowiq
FlowIQ staff CLI. Round-trips agent prompts, questionnaires, fine-tuning,
contact chats, platform webhooks, outbound messaging webhooks, FlowMod
master-group prompts, Pin Board tasks, WhatsApp templates, agent-update
requests, full chat exports, and live agent testing through
https://api.flowiq.live/cli/* so the Supabase service role never leaves the
server.
Install
npm i -g @flowapt/flowiq-cli
flowiq --version # should print 0.1.xAuthenticate
Default flow — browser login (like npm login):
flowiq auth loginThe CLI shows a short code (e.g. FQ4X-9KTB), opens
https://app.flowiq.live/cli-auth when you press ENTER, and waits. A
logged-in FlowIQ super admin confirms the code on the page matches the
one in your terminal and clicks Approve — the CLI then receives a
freshly-minted personal key automatically. Never approve a code you
didn't just see in your own terminal.
Fallbacks (CI / no browser):
flowiq auth login --token fiq_staff_… # supply a key directly
flowiq auth login --paste # prompt for a key on stdinYour key is saved to ~/.config/flowiq/auth.json with chmod 600. To
verify what you're authenticated as:
flowiq auth whoamiTo rotate this device's token (mints a fresh key, revokes the old one server-side — run whenever you want a new secret):
flowiq auth refreshTo log out (deletes the local key file, does NOT revoke the key
server-side — use flowiq auth refresh first if you want the old key
dead, or ask another super admin to revoke):
flowiq auth logoutCommands
All pull commands write to ./.flowiq/<topic>/<slug>.json relative to
your current working directory. We recommend picking a dedicated folder
for your CLI work:
mkdir -p ~/flowapt-cli && cd ~/flowapt-cliPrompts — flowiq prompts pull|push <slug>
Round-trips an org's active WhatsApp agent's system prompt
(agents.settings.prompt_sections).
flowiq prompts pull <organization_id>
# edit ./.flowiq/prompts/<slug>.json — modify section titles/content
flowiq prompts push <slug>Notes:
system_promptis regenerated server-side fromprompt_sectionson push using the## SECTION: <title>format.- Sections support optional
hidden: boolean+channels: string[](web/whatsapp/messenger/instagram) — validated on push. - For legacy agents without a sections array, pull auto-bootstraps a
single "Main" section from
settings.system_promptand returnsbootstrapped: true. The CLI prints a heads-up before push.
Questionnaires — flowiq questionnaires pull|push <slug> (alias q)
Round-trips agents.questionnaire JSONB.
flowiq q pull <organization_id>
# edit ./.flowiq/questionnaires/<slug>.json — fill in answers
flowiq q push <slug>If the DB column is null, pull seeds the local file from a default
template (9 sections / 23 questions). Optional per-question note field
is preserved round-trip.
Fine-tuning — flowiq fine-tuning pull|push <slug> (alias ft)
Round-trips agents.fine_tuning (text instructions) + agents.fine_tuning_entries
(structured Q&A entries).
flowiq ft pull <organization_id>
# edit ./.flowiq/fine-tuning/<slug>.json
flowiq ft push <slug>Each entry has: id, customer_question, correct_answer, agent_answer,
notes, date (YYYY-MM-DD), category (Product Info / Pricing / Warranty /
Shipping / Returns / Promotions / Technical Support / Tone Adjustment / Other),
suggested_tone (Friendly / Professional / Encouraging / Brief / Detailed),
status (Pending / Resolved), messages: [], media: [].
Knowledge / text sources — flowiq knowledge pull|push|list (alias kn)
Round-trips an agent's text knowledge sources — the { code, text } entries
in agents.additional_config that the agent's get_more_answers tool retrieves
on demand (brand references + tethered playbooks; the "Knowledge Sources → Text"
tab in the UI).
flowiq knowledge pull <org_id> # → ./.flowiq/knowledge/<slug>.json (sources[] = {code,text})
flowiq knowledge pull <org_id> --agent <id> # a specific (non-active) agent
flowiq knowledge push <slug> # FULL-REPLACE sources[] back onto the agent
flowiq knowledge list- Codes are
UPPER_SNAKE(^[A-Z0-9][A-Z0-9_]{2,63}$), validated server-side. Edit / add / remove entries insources[], then push (full-replace of the array). - Object-shape guard: some agents use
additional_configfor Flowapt-managed config (external_woo_build, …) rather than text sources — a pull flags that, and a push is refused (never clobbers managed config). --agent+ filenames behave likeprompts(a non-active agent saves to<org-slug>-<agent-slug>.json). The file carriesagent_id, sopushtargets the agent it was pulled from.
Messages — flowiq messages pull <contact_id> (alias m)
Read-only pull of a contact's helpdesk_messages history. Anchors on the
Nth-most-recent user-* message, then grabs every row from that anchor
onward (all sender types — bot-, tool-call, member, human-, broadcast,
call-*, system, etc).
flowiq m pull <contact_id> --count 25
# writes ./.flowiq/messages/<contact-slug>-<org-slug>.json--count defaults to 25, max 200.
Webhooks (Shopify/WooCommerce) — flowiq webhooks pull|push|reconnect (alias wh)
Round-trips the inbound Shopify or WooCommerce platform webhooks (the "Active Webhooks" panel on the Configuration page).
flowiq wh pull <organization_id>
# auto-detects platform from the org row
flowiq wh push <slug> # create any topic in the JSON not currently live
flowiq wh push <slug> --prune # also delete any live webhook not in the JSON
flowiq wh reconnect <slug> <webhook_id> # WooCommerce-only: flip back to status=active- For orgs with
feature_flags.ip_whitelist === true(e.g. customers on Wordfence), all calls are routed via python-render's static-IP proxy. --pruneis direct-mode only (python-render proxy has no delete route) — on ip_whitelist orgs prune prints a clear "delete via store admin UI" message instead.- Reconnect is WC-only. Shopify webhooks are always active when present.
Messaging webhooks — flowiq messaging-webhooks pull|push (alias mw)
Round-trips the outbound messaging webhooks in the meta_webhooks
table (the right-hand panel on the Configuration page — these tell
FlowIQ where to POST when a customer messaging event fires).
flowiq mw pull <organization_id>
flowiq mw push <slug> --dry-run # diff preview, no writes
flowiq mw push <slug> # FULL-REPLACE: deletes every row, then inserts the JSONPush is full-replace — if someone added a row via the UI between your pull and your push, it gets wiped. Pull-edit-push within one session.
Validation: platform ∈ {whatsapp, web}, type from the per-platform
allowed enum, valid http(s) URL, no duplicate (platform, type, url)
tuples.
FlowMod prompts — flowiq flowmod pull|push <slug> (alias fm)
Round-trips a FlowMod org's master-group prompts + config. FlowMod groups
are a separate system from regular WhatsApp agents — their prompts live in the
flowmod_master_groups (model/pre-filter/config/signatures/custom_tools) and
flowmod_prompts (the main / extra prompt rows, keyed by master_group_id)
tables, read per-message by the flowmod-group-* webhooks.
flowiq flowmod pull <organization_id>
# edit ./.flowiq/flowmod/<slug>.json
flowiq fm push <slug>The pulled JSON has a master_groups[] array; each entry carries its editable
fields plus a prompts[] array ({ id, type, group_ids, text, data }). Push
updates only editable columns — prompt text/data/group_ids/type, and
master-group name/description/config/pre_filter_prompt/events_markdown/
custom_signature*/custom_tools — scoped by row id; it never touches PKs,
FKs, or timestamps, and there's no system_prompt regeneration (FlowMod reads
the prompt rows directly).
Common uses: edit a master-group's moderator prompt, or flip its reasoning
effort via config.reasoningEffort (none / low / medium / high).
Group chats — flowiq groups list|pull <name-or-jid> (alias grp)
Read-only pull of WhatsApp group chat history (e.g. the … x Flowapt
client comms groups) straight out of the FlowMod Evolution Postgres. This
is the analogue of messages pull, but for a group instead of a contact, so
you can pull a window and summarise it.
⚠️ Unlike every other command, this talks to a database directly (the Evolution DB is not Supabase and not the
fiq_staff_…API). To keep this published package secret-free, the connection string comes from your shell environment — setFLOWMOD_EVO_DB_URL(or the fiveFLOWMOD_DB_*vars theflowmod-copilotedge fn uses) before running. No auth token is needed.
export FLOWMOD_EVO_DB_URL='postgres://user:[email protected]:5555/flowiq-db'
flowiq groups list # default instance: flowapt
flowiq groups list --instance FlowMod # the other connected instance
flowiq groups pull "Phytoceutics x Flowapt" --last 7d
flowiq groups pull "Zorora x Flowapt" --since 2026-06-24 --until "2026-06-25 12:00"
flowiq grp pull [email protected] --last 48h # or pass the group JID
# writes ./.flowiq/groups/<instance>-<group-slug>.json + prints a timeline- Group is matched by JID, exact name, or a unique case-insensitive substring (ambiguous matches list the candidates and exit — pass the JID to disambiguate).
- Window:
--last <48h|7d|2w|90m>(default48h), or an explicit--since/--until(SAST;--untildefaults to now).--limit(default 1000) keeps the most-recent N in the window. --jsonprints the full payload to stdout instead of the timeline.- Read-only — there is no
push; group history is a system of record. View-once/disappearing messages and raw media bodies can't be read (captions and text come through); history before the instance joined a group may be gappy.
Pin Board tasks — flowiq pinboard pull|push|list|list-remote (alias pin)
Round-trips a single internal Pin Board task (flowapt_tasks row).
flowiq pin list-remote open # find the task id you want
flowiq pin pull <task_id> # → ./.flowiq/pinboard/<slug>.json
flowiq pin push <slug> # writes editable fields back, stamps updated_atEditable fields: name, description, status (open / in_progress / done),
urgency (low / normal / high / critical), preferred_due_date (YYYY-MM-DD or
null), organizations[], media[], messages[], created_by. Array columns
are full-replace within the row.
WhatsApp templates — flowiq templates pull|list|create|status (alias tpl)
Read an org's live templates straight from Meta (read-only), and submit new
ones through the create-meta-template edge function.
flowiq templates pull <organization_id> # → ./.flowiq/templates/<slug>.json (Meta-side truth)
flowiq templates create <organization_id> --request-file req.json
flowiq templates status <organization_id> --name booking # poll approvalreq.json holds { template_request, template_data?, media_header?, cards_media? }.
Media headers: pass media_header.file_url (a public URL) — the edge function
uploads it to Meta server-side. Approval is async; re-pull for the
authoritative Meta status.
Org info — flowiq org info <organization_id>
Read-only platform detect + active-agent lookup for an org (raw store/Meta credentials are stripped server-side).
flowiq org info <organization_id> # platform, storefront url, active agentAgents — flowiq agent list|create <org>
List an org's agents (to discover ids) and create a new one.
flowiq agent list <organization_id> # ★ marks the active agent; shows each id
flowiq agent create <organization_id> --name "Zara" \
--system-prompt-file ./zara-prompt.txt --make-activecreate inserts a new agent (created_by = your staff-key identity), optionally
seeds its prompt into a single "Main" section, and — with --make-active — sets
it as the org's active_whatsapp_agent. New agents start on the app default
model; set the house model afterwards with agent config … --model gpt-5.4-mini
--use-settings-prompt.
Targeting a specific agent — --agent <id>
By default prompts, questionnaires, fine-tuning, and agent config all act
on the org's active agent. To target a different agent, pass --agent <id>
(get ids from agent list):
flowiq prompts pull <org> --agent <agent_id> # pull a NON-active agent's prompt
flowiq prompts push <slug> # pushes back to that same agent (id is in the file)
flowiq agent config <org> --agent <agent_id> --model gpt-5.4-minipull records the agent id in the JSON, so push always writes back to the exact
agent you pulled from (never "whatever is active now").
Filenames: the active agent saves to <org-slug>.json; a non-active agent
(pulled with --agent) saves to <org-slug>-<agent-slug>.json. So pulling
multiple agents from one org produces distinct files that don't overwrite each
other. (Fixed in 0.1.9 — before that, both used <org-slug>.json.)
Agent config — flowiq agent config <organization_id> [flags]
Set an allowlisted set of the active agent's config fields (the prompt-builder "Step 5"). With no flags, prints the current config.
flowiq agent config <organization_id> # show current
flowiq agent config <organization_id> --use-settings-prompt --model gpt-5.4-mini \
--rename Zara --tool woo_order_build=true --tool view_cart_tool=true --discount trueSettable: settings.use_settings_prompt, settings.model, agent --rename,
the tool-flag columns (woo_order_build, woo_tip_field, woo_order_note_field,
view_cart_tool, restock_tool, block_tool_status, postal_code_tool_status,
shopify_products_web_chat), and discount.enabled. Anything else is rejected;
every change is reported before → after.
Agent updates — flowiq agent-updates pull|list (alias au)
Read-only pull of an org's client-raised "change the agent" requests
(agent_updates), each with the chat context around the triggering message +
the linked contact. Attachments are downloaded locally.
flowiq au pull <organization_id> # pending, with context
flowiq au pull <organization_id> --status all --titles "EFT, bank"
flowiq au pull <organization_id> --before 20 --after 10 --no-files
# → ./.flowiq/agent-updates/<slug>.json + files/<update-id>/<attachment>Chat export — flowiq export chats <organization_id> [--out <path>]
Full chat history → TXT, byte-identical to the in-app "Export Settings TXT" (keyset-paginated server-side so it can't time out on big orgs).
flowiq export chats <organization_id> # → ./.flowiq/exports/<slug>-chats.txt
flowiq export chats <organization_id> --out ./phyto-chats.txtAgent testing — flowiq test <subcommand>
Drive an org's live agent through the web/test channel and read the reply back — never sends a real WhatsApp (the web branch only inserts the reply).
flowiq test send <organization_id> "What are your bestsellers?" --clear
flowiq test send <organization_id> "What is this?" --image https://…/photo.jpg
flowiq test qa <organization_id> # bundled generic smoke pack
flowiq test scenario <organization_id> ./pack.json # your own pack (expect/expectNot)
flowiq test clear <organization_id>
# phase 2 — adversarial parallel stress:
flowiq test stress <organization_id> ./stress.json --concurrency 6
flowiq test extract <organization_id> # rebuild transcripts for a judge
flowiq test cleanup <organization_id> --confirm # delete the stress contacts--agent <id> targets a specific (non-active) agent. test stress cleanup is
destructive and requires --confirm.
Environment variable overrides
| Var | Default | Use |
|---|---|---|
| FLOWIQ_API_URL | https://api.flowiq.live | Override the API host (local dev, staging). |
| FLOWIQ_TOKEN | (saved in ~/.config/flowiq/auth.json) | Override the auth token, useful for CI. |
| FLOWMOD_EVO_DB_URL | (none) | Full postgres:// URL for groups (Evolution DB). Required for groups. |
| FLOWMOD_DB_HOST/PORT/USER/PASS/NAME | (none) | Alternative to FLOWMOD_EVO_DB_URL — assembled into a connection string. |
Upgrading
When a new version ships, just re-run:
npm i -g @flowapt/flowiq-cli
flowiq --versionYour saved token in ~/.config/flowiq/auth.json is preserved across
upgrades.
License
UNLICENSED. Internal staff tool — install requires a valid fiq_staff_…
key issued by a FlowIQ super-admin.
