Skip to main content
Uses: CLI · Claude Code · Codex
Flo holds a shell and your API key, and can do anything your key can do. This page says what Flo is told never to do, what actually stops it, and where that protection ends. Read it before you rely on Flo, and keep it in mind when you choose the key you give it.

What Flo will never do

Four tools are the only ones Flo refuses by name - the never-verbs:
  • engini_workflows_delete_workflow
  • engini_workflows_run_workflow
  • engini_workflows_enable_or_disable_workflow
  • engini_workflows_rerun_execution
In plain words: Flo never turns a workflow on or off, runs it, reruns an execution, or deletes a workflow. It also never creates or changes a connection and never handles your API key.

The layers

Four layers stand between those four verbs and your account. Only the last one is a boundary, and it refuses nothing:
  1. Flo’s instructions name them as never. This is prose: a model follows it, nothing enforces it.
  2. Flo’s guard hook - Claude Code only. Installed with the plugin and live at once. See The guard.
  3. Your own settings - the settings below. Copy-paste; a plugin cannot install them for you.
  4. The Engini server refuses nothing here: your key is allowed to do all of it.
Codex has no hook. In Codex, the rules file you paste from Codex rules file is the only layer besides Flo’s instructions. If you skip it, nothing enforces the four verbs at all.

The guard (Claude Code only)

The guard is a hook installed with the plugin. It needs Python 3.8 or later (python3 or python) and refuses these:
  • The four never-verbs. An engini tools call naming any of them is refused in any argument order and through quoting, case and bash -c wrappers. A tool name the guard cannot read (built from a shell variable or a substitution, such as engini_workflows_$V) is refused too, because it could be one of the four.
  • Commands that handle a raw key: engini connect, engini login, engini connections create|update|delete, engini connections auth-providers create|update, and any --api-key.
  • Reads of your stored login and of key variables: reading the CLI’s stored login (see Where the CLI stores your login), an ENGINI_API_KEY / ENGINI_API_TOKEN / ENGINI_COMPANY_TOKEN variable, or dumping the environment. A presence test such as [ -n "$ENGINI_API_KEY" ] is fine.
  • Edits to the hook itself or to your Claude Code or Codex settings. This includes any command that names your .claude or .codex folder itself, a wildcard name or a ./.. step inside one, or a cd into a folder under one - so even ls ~/.claude is refused. Read, Write, Edit, Grep and Glob paths are judged as given and again after resolving them against the session’s folder and following symlinks.
An engini tools call with a heredoc is judged as code unless it is Flo’s own one-call shape: the <<'EOF' opener ends the command’s first line and the reader is the engini CLI itself (engini, npx @engini/cli or npx @engini/cli@<exact version>).

Scope of the guard

The guard applies to every Claude Code session where the plugin is enabled - not only while Flo is working. It also refuses your own engini connections delete, or a never-verb you genuinely meant to run. Run those in your own terminal, or turn the plugin off for the session with /plugin disable flo@engini-flo (that removes the guard’s other protections too). Everything else - your builds, git, other tools, other Engini apps’ tools - runs normally.
This applies to every project’s own .claude and .codex folders too. With the plugin enabled, ls .claude, git add .claude, grep -r x .claude and a cd into a folder inside .claude are refused in every project and every session, not only while Flo is working. Run those in your own terminal, or turn the plugin off for the session.

When the guard refuses something

The message starts with FLO-HOOK-DENY and says which of these it is: The plugin’s troubleshooting guide covers each case in more detail. Claude Code’s own deny rules (layer 3) also catch the four verbs inside a compound command such as cd /tmp && engini tools call ... - tested on Claude Code 2.1.316. The guard’s extra reach is that it needs no paste, and the quoting and wrapper forms above.

What the guard does not stop

While Flo has a shell and your key, it can do anything your key can do, including acting through your other connections. The guard narrows one literal command form. It is a text matcher, not a sandbox. These are deliberately open, and tested as open:
  • Every other tool. The guard refuses only the four verbs. Flo’s rule against calling other apps’ tools (for example slack_send_message) is an instruction Flo follows, not something enforced; so is “read execution data only when asked”. Builder tools Engini adds later run normally too.
  • Indirection the guard never sees: eval "$X", bash -c "$X", a shell function, a script file.
  • Anything that skips the CLI: a python -c against the SDK, or a plain HTTPS call with your key.
  • A tool name that is never in the command text at all, for example xargs engini tools call --args - < slugfile.
  • The key file reached through a glob (cd ~/.config && cat engini/conf*), a recursive search from a parent folder in the shell (grep -r ... ~/.config), and a custom XDG_CONFIG_HOME folder named by its own path in a shell command.
  • A settings folder name built from a variable or a wildcard in the folder name itself (~/.cl*).
  • In the shell, a symlink to your settings or key folder that already exists (the command names only the link), and a program that changes folder itself before it writes (os.chdir in a script, git -C, find -execdir). Read, Write, Edit, Grep and Glob follow symlinks, so those tools are covered.

Settings to paste yourself

Each rule below matches the literal command form only. bash -c, a shell variable, eval, reordered arguments or a python -c against the SDK walk past every one of them. They are what holds when the guard does not run, and in Codex they are all there is.
  • Allow only Bash(engini:*) and never run Flo on auto-accept or --dangerously-skip-permissions. Flo holds a shell and your key; this is the widest control by far.
  • The two ask rules make Claude Code ask you, outside the conversation, before every create or update - the one approval the model cannot give itself.
  • The Read rules cover the stored login on each platform for Claude’s own file tools; they do not bind a shell command, and the one Bash(cat ...) rule covers only that exact command. What keeps other shell reads (grep, head, the other paths) from running unasked is that Bash(engini:*) is the only allow rule, so any other command asks you first.

Claude Code settings

Merge this into your user settings (settings.json in your ~/.claude folder):

Codex rules file

Save this as ~/.codex/rules/flo.rules:
Codex support is not yet verified on a real Codex install. If commands are not refused in Codex, check that this file exists and that you started a new session after saving it.

Codex sandbox

Codex runs commands without network by default, so every engini call fails. Allow network for commands in your Codex config:
Or approve the commands outside the sandbox. Flo’s optional session log and lessons live in ~/.engini/flo/, outside the workspace: add it as a writable root or Flo skips them. Not yet verified on a real Codex install.

Where the CLI stores your login

The guard refuses reads that name any of these paths, and Grep or Glob searches started from a folder above them, such as your home folder or ~/.config - however that folder is spelled: a relative path, no path while the session runs in it, a symlink, or a second macOS name for your home folder such as the one under /System/Volumes/Data.
  • ~/.config/engini/config.toml (macOS, Linux)
  • $XDG_CONFIG_HOME/engini/config.toml (when XDG_CONFIG_HOME is set)
  • %APPDATA%\engini\config.toml (Windows)
  • %USERPROFILE%\engini\config.toml (Windows, when APPDATA is unset)
For how the CLI stores credentials, see the CLI overview.

Things to know

  • Your key carries its creator’s whole permission set. Use a dedicated, least-privilege, workspace-scoped key you can rotate. See API keys.
  • Log in interactively. engini login, never --api-key on the command line.
  • What Flo reads enters the model’s context: workflow definitions, and execution data when you ask for it.
  • The stored key is reachable by the agent. It is a file in your own home folder; the agent can reach it through the shell as much as through file reads. The guard refuses the literal reads; what actually protects you is a scoped, rotatable key plus the Bash(engini:*) allow rule - not secrecy from the model.