Synopsis
feral CLI is the primary interface for managing the FERAL brain, dashboard, and development tools.
Global connection options apply to all subcommands:
Commands
feral (no subcommand)
Launch the interactive REPL. Connects to the brain via WebSocket and presents a chat prompt.
/status, /devices, /skills, /identity, /quit.
feral "message"
One-shot mode. Sends a single message to the brain, prints the response, and exits.
feral start
Start the brain, wait for health, optionally open the dashboard in a browser, then drop into the interactive REPL. If this is the first run, the setup wizard launches automatically.
feral serve
Start only the brain API server (headless, no REPL, no browser).
Useful for production deployments or when running the dashboard separately.
feral setup
Run the interactive setup wizard.
feral status
Show the current state of the running brain (sessions, devices, skills, LLM, audio, sync, memory).
feral devices
List all connected hardware devices.
feral skills
List all loaded skills.
feral identity
Show the agent’s name, personality, rules, and communication style.
feral pair
Manage per-node device pairing tokens for session authentication.
feral access
Manage pairing access mode and remote tunnel state.
feral wake-test
Test wake word detection from your microphone for 10 seconds.
openwakeword and pyaudio. Reports detection count and mode (ML or energy-based fallback).
feral marketplace
Skill marketplace commands.
feral sync
Federated memory sync commands.
feral doctor
Run comprehensive diagnostics and report what’s working, what’s missing, and suggested fixes.
feral update
Upgrade feral-ai in the environment that is actually running the brain, then restart it.
sys.executable, the interpreter running this command, not whatever pip your PATH resolves first. That distinction is the point: a machine with more than one Python environment will happily upgrade the one that is not serving, which reads as an upgrade that did nothing.
It refuses rather than half-works. A source checkout (pip install -e) is sent to git pull instead of pip. A brain running under a different interpreter than the CLI is reported, with the command that would work, rather than silently skipped. Running it when you are already current does nothing and says so.
The restart afterwards is not decoration: a Python process never reloads its source, so an upgrade without a restart leaves the old code serving. It reuses feral restart.
Checking for releases on a schedule is separate and off by default (see FERAL_UPDATE_CHECK in the environment reference). feral update asks the index when you run it, because running it is the request.
feral key
Manage per-provider API keys in the encrypted vault. Multiple labeled keys per provider are supported, and add probes the key before the prompt closes so you see green/red immediately.
add, list, remove, reset-cooldowns, recover.
feral models
List, test, and pin the chat model per provider.
feral voice
Inspect and test the STT / TTS / realtime voice catalogue. providers shows the same probe status the setup wizard’s voice preflight renders.
feral integrations
Connect and disconnect third-party accounts. OAuth providers support --self-hosted to use your own OAuth app instead of a first-party client.
gmail, google, notion, spotify, microsoft, home-assistant.
feral grant
Grant or revoke folder access for the computer_use file tools. Paths outside an active grant are refused, and grants apply immediately without a restart.
feral twin
Manage the digital twin’s per-domain policies and its approval queue.
feral checkpoints
Inspect or undo the file writes FERAL made, grouped by the user message
(the “turn”) that caused them.
TURN_ID defaults to the most recent checkpointed turn. show prints the
revert plan without touching a file.
A file whose current content no longer matches what FERAL left there is reported
as drifted and the revert refuses outright. --force overrides that and
discards the newer content.
This command reads $FERAL_HOME/checkpoints/index.db directly and never calls
the brain’s REST API, because the moment you most need an undo is the moment the
brain is wedged. See Coding Harness.
feral memory
Memory backend, decay, and query management.
feral app
Build, sign, and publish GenUI app bundles.
sign uses your publisher key at ~/.feral/publisher.key; there is no --private-key flag.
feral app install asks first
Installing an app is two steps, because an app’s skill_dependencies install
skills and a skill executes Python inside the brain. install calls
POST /api/apps/preview, prints what it found, asks, and only then calls
POST /api/apps/install with the install_token the preview minted. The route
answers 403 preview_required without one, so there is no unattended path.
What it prints, all of it served by the brain so the terminal and the web
install sheet cannot drift:
- the bundle’s signature status, and the app’s own reach (where its sandboxed surfaces may send data),
- skills it will install: new code, each verified against its publisher’s signature, with what each one can reach,
- skills you already have: nothing new runs, listed so the app’s full reach is visible,
- skills FERAL cannot install: the brain’s own reason, the actions that will not work without them, and what to do about it.
GET /api/apps recomputes missing_skill_dependencies on every
call, so the Apps page keeps showing the shortfall until the skill is there.
Exit codes:
0 installed, 1 declined or refused, 2 bad invocation. A
non-TTY stdin never prompts. Piped or scripted, without --yes, it prints the
disclosure, installs nothing and exits 2 naming the command that would work; an
answer read off a pipe is not consent.
feral bridge
Install the phone-bridge daemon on this host.
feral install
Install a published skill or daemon from the FERAL registry. The argument is
the item’s name (the skill_id for a skill, and what the catalog lists);
the registry’s UUID also resolves, but nothing you type should be one.
feral publish
Publish a skill or daemon bundle to the registry. --skill and --daemon are mutually exclusive and one is required.
manifest.json at its root (a SkillManifest
or DaemonManifest, not a registry envelope), with impl.py or your
entrypoint beside it. The registry metadata is derived from that manifest, and
the item publishes under its identifier: skill_id for a skill, node_id for
a daemon. Your brand.name is a display name and is not the key.
A publish is a submission. It lands submitted / private and is not
installable until a reviewer approves it; the command prints the status it got
back and the endpoint to track it. See
Marketplace → Publish flow.
feral publisher
Manage the publisher identity used by feral publish.
