Skip to content

Place orders via interactive confirmation (no bypass/passphrase) - #117

Merged
eaitbrahim merged 1 commit into
mainfrom
feat/interactive-confirm
Jul 21, 2026
Merged

Place orders via interactive confirmation (no bypass/passphrase)#117
eaitbrahim merged 1 commit into
mainfrom
feat/interactive-confirm

Conversation

@eaitbrahim

Copy link
Copy Markdown
Contributor

Option A, as agreed: placing a live order no longer needs bypass mode, the arm-bypass token, or the dangerous-action passphrase. In confirm mode the agent shows the previewed order and asks; it places only on an explicit yes. Bypass mode is untouched and stays the headless path for future autonomous use.

The rails are untouched — this is important

Every order still runs the 15 hard rails first. The confirmation is an additional human gate after they pass, never a replacement. There's a test pinning that a rail-vetoed order never reaches the prompt — the rails run first, the human second. So removing the bypass ceremony did not weaken any hard limit.

Why this was small

The executor was already built for it — execute takes confirm_fn(preview) -> bool; the agent just hardcoded it to None. This threads a real confirm_fn through run_once / loop / _handle_exits (all defaulting to None, so every existing caller and test is unchanged and still fails closed), and keel agent passes an interactive prompt in confirm mode.

_interactive_confirm renders the broker preview and asks; it fails closed on a non-TTY, so a script or cron never trades unattended.

Net effect

Placing an order goes from:

python3 -c "authz.set_passphrase(...)"   # no CLI for this
keel arm-bypass --passphrase ...
keel agent --bypass --passphrase ...

to:

keel agent
  Rails PASSED. Coinbase order preview:
    order_total: 5.00 ...
  Place this order? [y/N]: y

Arguably safer for supervised use — a human looks at the real order every single time instead of pre-authorizing a window.

Tests

approved → places the BUY (+ its OCO bracket); declined → nothing; no confirm_fn → still nothing (backward compat); confirm_fn sees the preview; a rail veto never reaches the prompt; _interactive_confirm yes/no/non-TTY; and the agent command wires the interactive prompt in confirm mode, None in bypass.

Follow-ups (not in this PR)

1266 tests pass (up from 1258), ruff clean.

🤖 Generated with Claude Code

Option A: placing a live order no longer requires bypass mode + the
arm-bypass token + the dangerous-action passphrase. In confirm mode the
agent now shows the previewed order and asks the operator; it places only
on an explicit yes. Bypass mode is UNCHANGED and remains the headless
path for future autonomous use.

⚠️ THE RAILS ARE UNTOUCHED. Every order still runs the 15 hard rails
FIRST; the confirmation is an ADDITIONAL human gate after they pass,
never a replacement. A test pins that a vetoed order never reaches the
prompt (rails run first, confirmation second).

The executor was already built for this (`execute` takes
`confirm_fn(preview) -> bool`); the agent just hardcoded it to None. This
threads a real `confirm_fn` through `run_once`/`loop`/`_handle_exits` (all
default None, so every existing caller and test is unchanged and still
fails closed), and `keel agent` passes `_interactive_confirm` in confirm
mode / None in bypass.

`_interactive_confirm` renders the broker preview and prompts; it FAILS
CLOSED on a non-TTY (a script/cron never trades unattended), same posture
as everything else.

Net: placing an order goes from "set-passphrase -> arm-bypass ->
--bypass --passphrase" to "run keel agent, answer y" -- and is arguably
safer for supervised use, since a human sees the actual order every time
instead of pre-authorising a window.

Tests: approved->places the BUY (+ its OCO bracket); declined->nothing;
no confirm_fn->still nothing (backward compat); confirm_fn sees the
preview; a rail veto never reaches the prompt; _interactive_confirm
yes/no/non-TTY; the agent command wires _interactive_confirm in confirm
and None in bypass.

NOTE: the go-live runbook (PR #116, unmerged) still describes the old
bypass/passphrase dance and must be rewritten against this once both land.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@eaitbrahim
eaitbrahim force-pushed the feat/interactive-confirm branch from 40e0668 to f67c553 Compare July 21, 2026 22:43
@eaitbrahim eaitbrahim added the feature New capability (groups under Features) label Jul 21, 2026
@eaitbrahim
eaitbrahim merged commit eb9c417 into main Jul 21, 2026
1 check passed
@eaitbrahim
eaitbrahim deleted the feat/interactive-confirm branch July 21, 2026 22:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New capability (groups under Features)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant