chat command talks to a messaging agent
through a separate terminal endpoint.
Try the starter
Startnpm run mcp in one terminal. In another terminal in the same project:
menu --json prints the café’s menu as JSON. order --help lists the
commands for placing and tracking orders.
Define your commands
Install the optional peers when adding a CLI to an existing project:src/cli.ts defines your product’s command names, groups, arguments and output:
--json and --fields; writes support --dry-run, and actions that can delete
or overwrite require --yes without an interactive terminal. Add your own Stricli commands
alongside the generated tool commands. Handwritten commands execute locally without discovery,
including their help and argument parsing; an explicit this.cli.call(...) calls MCP. A handwritten
command takes precedence over a derived command with the same name. flow check checks that your
CLI configuration still matches the tools.
sections groups top-level commands and groups under headings in the order declared; remaining
commands appear under Other. chat, when configured, comes first; built-in commands appear under
This CLI. flow check rejects unknown names and a name listed in more than one section.
Run cafe help order to find commands whose names or descriptions contain every supplied word.
Format results for people
Addoutput and format to a tool to share readable
Markdown across MCP and the CLI. A command without columns or view prints that text by
default; --json and --fields keep using the structured result.
For terminal rendering, install these optional peers:
{ order_id: "BL-1040", ready_by: "10:30" }, the example formatter prints
Order BL-1040 is ready by 10:30. Piped output, NO_COLOR, and installations without these
peers print the Markdown as written. A formatter error falls back to JSON and records
formatError on tool.end; it does not turn a successful operation into a failure.
For an account-protected server, run the CLI’s auth login command. It signs the person in with
OAuth; automation can use the configured token environment variable instead. The account and
permissions are verified by the same MCP server.
Run npx @flow-engineer/flow cli --server <url> --help for a generic CLI over an existing MCP
server. Always use the full package name with npx; npx flow fetches a different package.
Common commands
order status result depends on whether that order exists in the running café server.
--dry-run previews the operation without invoking the write tool.
List and read skills
Useskill as a catalog and reader, without loading every skill body:
list shows names and descriptions, including the generated cafe-cli guide
and the café’s allergens workflow. get allergens prints that skill’s full instructions. The
last command returns two named records, each with name, description and content; no other
skill bodies are read. Replace cafe-cli with <your-cli-name>-cli in your own project.
Bare skill is the same as skill list. skill list --json returns only names and descriptions;
skill get <name> [name...] --json returns an array even for one selected skill. The generated
CLI guide includes handwritten commands and maps MCP tool names to configured CLI command paths.
Workflow instructions come from the same agent/skills/ source used by MCP and messaging.
To install selected skills:
<dir>/<skill-name>/SKILL.md for each selected skill. Additional source assets are
not copied; use native plugin packaging to distribute those. The existing
skill --write <dir> command continues to export only the generated CLI guide. A handwritten
workflow with the same name takes precedence in the catalog; the legacy export still produces
the generated guide.
Use the standalone MCP endpoint (/mcp) for workflow skills. Its existing read_skill descriptor
advertises names and descriptions in _meta["flow.engineer/skills"]; bodies are fetched only by
get. Older MCP servers without this metadata still expose names through the reader’s schema,
with empty descriptions. Unknown names trigger one discovery refresh before the CLI reports an
error. All requested names are checked before a batch is read or exported.
Cached discovery and server updates
MCP-backed commands execute on your deployed MCP server; ship that server alongside the CLI. The CLI caches tool definitions and the server’s name/version in~/.config/<name>/discovery/
(XDG_CONFIG_HOME or CliConfig.directory overrides the location). Entries are scoped to the
endpoint, client and credentials. Discovery files have mode 600 and contain no credentials or tool results.
Cached definitions load immediately, including older snapshots. Help, tools, skill and dry
runs do not wait for a server check. Once a snapshot is five minutes old, a background refresh
checks the server and fetches current definitions. Installed CLIs use a separate process that
survives the command exiting, with a 15-second limit. Concurrent commands share one refresh;
background failures keep the previous definitions and do not add output.
Tool calls still connect and authenticate. If the server’s name or version differs, the CLI
fetches definitions and rebuilds the generated command’s parser and approval flags before sending
the call. Bump the MCP server’s version when changing tool contracts or safety annotations.
Periodic discovery also picks up changes when a server does not bump its version.
If an unknown command or invalid argument could be caused by an old cache, the CLI fetches current
definitions and reparses once before execution. If the server rejects arguments after a request
has been sent, the CLI refreshes definitions and reports the error with a help hint. It never
silently resubmits that request or reruns a handwritten command.
To force current discovery:
discoveryCache: false in defineCli to disable disk caching, or
discoveryCache: { maxAgeMs: 60_000 } for a one-minute background interval. Handwritten local
commands need no MCP server unless they explicitly call it; --refresh-tools opts into discovery.
If a handwritten command declares its own --refresh-tools flag, that flag keeps its local meaning;
use tools --refresh-tools for framework discovery.
Local playground CLI
Run the actual CLI inside a local playground
Run the actual CLI inside a local playground
A local playground can run the team’s actual CLI, including custom commands, OAuth, interactive
chat, confirmations, stdout/stderr and exit codes. Opt in on the server that runs on your computer:The named channel must be declared on the agent. Its tab opens the runner instead of simulated
chat. Each browser gets an independent temporary sign-in and conversation directory; the test
person picker does not grant it an account. Run
auth login, open the sign-in link, then return
to the runner. chat keeps reading input until /exit; reload reconnects to that session.
Clear output clears the viewport; New CLI session ends the session and removes its local
credentials, without clearing the account’s agent history. Sessions expire after 30 minutes
without browser activity, and a server restart starts fresh. Ending a session does not undo
work already accepted by the agent.This runner accepts only direct loopback connections with a loopback Host and same-origin API
requests, even if explicitly configured on a mounted handler. It is absent by default and is
not enabled in the hosted test cloud. It invokes runCli in-process: no shell, arbitrary program
execution, expansion or pipelines. Quoted arguments work. Its configured endpoints stay fixed;
use the installed CLI for --server, --token or skill --write.The browser CLI runner is available locally only. Hosted browser execution is not supported.Embedded clients can set CliConfig.directory to isolate credential/conversation/discovery files and
CliIO.env to avoid inheriting process tokens; CliIO.signal cancels sign-in and terminal HTTP
requests. CliIO.background(work) lets an embedded host schedule discovery refreshes without
delaying the response; invoke work while the session is alive. The local playground supplies this
scheduler and cancels refreshes when the session ends. Defaults retain the installed CLI’s existing
environment and config directory.Terminal conversations
A terminal conversation needs the optional agent terminal handler described below. Serving the
MCP endpoint alone enables tool commands; it does not add conversational chat.
chat talks directly to the agent, using the same bearer as MCP; it is not an MCP tool. defineCli({ name: "acme", server, agent: "https://agent.example.com/agent/terminal" })
overrides the terminal URL; the default is the MCP server’s origin plus /agent/terminal.
acme chat "Which orders are ready?" --json prints one response; acme chat reads a TTY until
Ctrl-D or /exit. Without a TTY pass a message to chat (an interactive chat exits 2); sign-in failures exit 3.
chat.json is mode 600 and scoped by terminal endpoint. --new forgets the terminal’s saved
reference; the agent keeps its one-person history across channels. It does not erase a person’s
WhatsApp history. Teams can replace chat with their own Stricli command in commands.
Mount the optional terminal handler beside MCP (no model or extra dependency in the CLI):
terminalServer accepts path and channel overrides. It verifies auth on every POST,
serializes concurrent requests per person, and returns { conversationId, replies } after the
turn settles. The authenticated key becomes the same person that resolve returns on other
channels. A body cannot choose its own person; a conversation reference from another person is
refused. Its custom UI uses Markdown and exports turns as channel cli.
For your own HTTP adapters, agent.request({ channel, key, text, conversationId? }) exposes this
without the handler. Supply a verified key and serialize calls for that channel and person.
Add another tool
New tools become commands automatically.
Inspect calls in production
The server records calls from the CLI, MCP and plugins.