---
title: "Slack interviews, hooks, model failover, and GPT-5.4"
date: "2026-03-05"
---

## Slack integration for interviews

Fabro can now conduct human-in-the-loop interviews directly in Slack. The new Slack Socket Mode integration supports all five question types — yes/no, confirmation, multiple choice, multi-select, and freeform (via threaded replies). Because it uses Socket Mode, no public URL or webhook endpoint is required.

Previously, interviews required the CLI or web UI. Now teams can answer Fabro's questions without leaving Slack.

## Hooks

Workflows can now trigger actions at key moments — before a stage starts, after it completes, or when a run fails. Use hooks to notify external systems, enforce policies, or gate execution on custom conditions.

Three executor types are available: `http` for calling external endpoints (with TLS mode configurable per-hook), `prompt` for natural-language conditions evaluated by an LLM, and `agent` for autonomous decision-making.

```toml title="run.toml"
[[hooks]]
event = "stage.before"
executor = "http"
url = "https://api.example.com/webhook"
tls_mode = "strict"
```

## Model failover

If your primary model is unavailable or rate-limited, runs now automatically switch to a backup. Configure fallback models at the provider level in your server config:

```toml title="server.toml"
[providers.anthropic]
failover = ["openai", "gemini"]
```

Previously, a provider outage would fail the entire run. Now it retries with the next provider in the list.

## GPT-5.4 and GPT-5.4 Pro

OpenAI's GPT-5.4 and GPT-5.4 Pro are now available in the model catalog. Use the aliases `gpt54` and `gpt54-pro` in your workflow stylesheets. Neither replaces GPT-5.2 as the default OpenAI model.

```dot
stage_a [model="gpt54-pro"];
```

## More

<Accordion title="CLI">
- Added `fabro parse` command for printing the raw AST of a DOT workflow as JSON
- Persistent CLI defaults in `~/.fabro/cli.toml` — set output format, default workflow, or any flag once
</Accordion>

<Accordion title="Workflows">
- Richer condition expressions: `||`, `!`, numeric comparisons, `contains`, and `matches` (regex)
- Per-node `max_visits` attribute overrides the graph-level `max_node_visits` setting
- `$$` escapes literal dollar signs in prompts, fixing a bug where `$goal` could match as a substring
- Simplified handler type names: `agent_loop` is now `agent`, `one_shot` is now `prompt` (old names still work)
</Accordion>

<Accordion title="Fixes">
- Fixed a server-side error message that could leak to the browser in production
- Fixed a crash in the web UI when loading run stages (`apiStages.map` on non-array response)
- Fixed Docker demo build and verifications API response parsing
</Accordion>

<Accordion title="Improvements">
- MODEL column in CLI tables widened from 24 to 30 characters to avoid truncating longer model names
- Unknown `$variable` placeholders in DOT prompts now produce clear error messages instead of being silently passed through
</Accordion>

<Warning>
**`script.output` and `script.stderr` context keys renamed to `command.output` and `command.stderr`.** The old names were inconsistent with the handler name (`command`).

To migrate: Update any DOT workflow prompts referencing `{{script.output}}` or `{{script.stderr}}` to use `{{command.output}}` and `{{command.stderr}}`.
</Warning>

<Warning>
**`GET /runs/{id}/compare` renamed to `GET /runs/{id}/files`.** The endpoint now returns a standard paginated list of `FileDiff` items instead of the `RunCompare` envelope.

To migrate: Update API integrations using `/compare` to use `/files`, and adjust response parsing from `{ checkpoints, files, stats }` to `{ data, meta }`.
</Warning>
