Sessions
fctl runStart one, and follow itfctl attachStream it and type messagesfctl logs -fThe transcript, as it growsfctl searchEvery transcript, by what was said
FeaturesThe CLI
Everything the app does, the CLI does too: start a session and watch it stream, steer it, search every transcript, manage projects, runners and schedules. And every command answers in JSON when a script, a pipeline or another agent is the one asking.
The CLI reference fctl for agents
fctl run -p shop "The farm photos on the box page are squashed on small phones. Keep them in proportion."
✓ shop#233 Keep the farm photos in proportion on small phones https://app.fctl.sh/s/ses_01K8ZW6QH3N5B1D7XKT2C4MVRE
▍ Noor Haddad
▍ The farm photos on the box page are squashed on small phones. Keep them in proportion.
◌ provisioning — Creating the sandbox on kohlrabi
Creating sandbox fctl-ses-01k8zw6qh3 from ghcr.io/hyperstructure/sandbox:0.23.1
Cloning romanescohq/shop
added 642 packages, and audited 643 packages in 6s
● running
⏺ Grep(farm-photo)
⎿ src/components/FarmCard.tsx:14: <img className="farm-photo" width={320} height={180} …
The photos have a fixed width and height and nothing that keeps their proportions, so a narrow card squashes them. I'll keep the size for layout and crop with object-fit.
⏺ Edit(src/components/FarmCard.tsx)
⏺ Bash(npx playwright test farm-card --project="iPhone SE")
⎿ 2 passed (6.1s)
fctl run and fctl attach stream the transcript as the app shows it, and take your messages.
Add --json to any command. Exit codes say what went wrong, so scripts can tell.
Another agent with the CLI and the docs at fctl.sh/llms.txt hands work to fctl and collects the result.
The same binary runs your hosts: install, status, drain, logs and its own updates.
fctl sessions lists what's at work and what finished, across your workspaces or in one, and
fctl show tells you everything about one: who asked, its ticket, its branch, its pull request
and checks, where it runs and how full its context is. Sessions go by shop#231, their id or
their link, whichever you have to hand.
fctl sessions -w romanesco --limit 6
infra#38 ● running Check production and staging for Terraform … 8m ago
shop#231 ● running Add Danish to the shop 1m ago
driver-app#77 ● running Show the delivery window on each stop 2m ago
platform#445 ○ idle Retry Stripe webhook processing that fails 21m ago
shop#230 ◍ paused Match the box builder to the new illustrati… 33m ago
shop#227 ○ stopped Update 9 npm dependencies 6h ago
fctl show shop#231
shop#231 Add Danish to the shop
Translates the shop for the Copenhagen launch: Lucía's copy from SHOP-419, prices in kroner and delivery days from the Copenhagen depot.
status: ● running
ticket: SHOP-419 Danish translations for the shop · https://linear.app/romanesco/issue/SHOP-419/danish-translations-for-the-shop
by: Tomás Ferreira
branch: fctl/231-add-danish-to-the-shop (from main)
pr: shop#1291 open, 12 of 23 checks pending https://github.com/romanescohq/shop/pull/1291
runner: kohlrabi
model: opus
effort: high
work: 1 turn · 21 tool calls · 4 files (+127 −4)
context: 46.5k of 200k tokens (23%) · compacts at 167k
https://app.fctl.sh/s/ses_01K8YD4T2W9QXN6B3HVM7CZRPE
A message reaches the agent at its next step, with files attached if you like. Interrupt the turn it's on, stop it, resume it tomorrow with a new task, or share it with a teammate. The same session is in the app, on your phone and in your terminal at once, and everyone sees the same thing.
Follow along and steerfctl send shop#231 -a dk-prices.png "Prices end in ,- in Denmark: 189,- not 189,00 kr."
✓ Sent to shop#231
fctl attach shop#231
▍ Tomás Ferreira
▍ Prices end in ,- in Denmark: 189,- not 189,00 kr.
Good catch. Danish shops write whole kroner as 189,- so I'll format DKK that way when the øre are zero, and keep 189,50 kr. otherwise.
⏺ Edit(src/lib/money.ts)
⏺ Bash(npm test -- money)
⎿ ✓ src/lib/money.test.ts (9 tests) 5ms
With -d, fctl run returns as soon as the session exists; with --json, it
says so in a form jq can read. Check on it when you like, read what it did, and move on: the
same commands work in a cron job, a GitHub Actions step, or another agent's tool call.
fctl login on your machine, FCTL_TOKEN anywhere else.id=$(fctl run -p platform -d --json -f tasks/flaky.md | jq -r .id)
# …once its turn has ended
fctl show $id --json | jq '{status, pr: .pull_requests[0].url}'
{
"status": "idle",
"pr": "https://github.com/romanescohq/platform/pull/846"
}
fctl memory -p platform --json | jq -r '.memories[0].text'
Answer Stripe's webhooks at once and do the work in the job queue (`jobs::enqueue`): a handler slower than Stripe's timeout gets the event again.
Every capability of the app has its command. A few of them:
fctl runStart one, and follow itfctl attachStream it and type messagesfctl logs -fThe transcript, as it growsfctl searchEvery transcript, by what was saidfctl projects setModel, setup script, image, sizesfctl projects secretsSecrets for its sandboxesfctl projects reposOther repositories it may usefctl projects ticketsLinear or GitHub issuesfctl review settingsTurn review agents onfctl review startReview a pull request nowfctl memoryWhat agents left for each otherfctl retro listHow each piece of work wentfctl host installTurn this machine into a runnerfctl host drainFinish its sessions, take no new onesfctl workspaces inviteBring someone infctl shareOne session, with one personfctl schedules addWork that starts on its ownfctl schedules runNow, with contextfctl tokenA token for a tool, with limitsfctl ticketTickets, from an agent's sandboxfctl loginThrough your browser and passkeyfctl claude connectYour Claude subscriptionfctl account two-factorAn authenticator appfctl self updateThe newest fctlEvery command and flag, and how programs should use them.
curl -fsSL https://fctl.sh/install | sh