Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
45195cc
feat(tui): palette for the 2026-10 screen language
chhhee10 Oct 10, 2026
157670f
feat(tui): building blocks for the 2026-10 screen language
chhhee10 Oct 10, 2026
fe69104
feat(config): remember which agents failproofai traces
chhhee10 Oct 10, 2026
78825ee
feat(policies): one shared answer to "is this machine enforcing?"
chhhee10 Oct 10, 2026
f3fc419
feat(tui): pickers in the 2026-10 screen language
chhhee10 Oct 10, 2026
7f9e3d8
feat(help): every help page in the 2026-10 screen language
chhhee10 Oct 10, 2026
247bdb3
feat(daemon): agent selection gates collection; scoped backfill requests
chhhee10 Oct 10, 2026
e9883dd
feat(tui): the cloud-key prompt, and a helper to collapse sudo's prompt
chhhee10 Oct 10, 2026
a28aa7f
feat(config): the v2 setup flow — key, agents, apply
chhhee10 Oct 10, 2026
b0d21a8
feat(policies): the policies screens in the new language
chhhee10 Oct 10, 2026
a944780
feat(config): status and pause in the new language
chhhee10 Oct 10, 2026
9fbb6bc
feat(launch): the dashboard launch screen in the new language
chhhee10 Oct 10, 2026
0d1086b
feat(audit): per-agent progress and the audit screens in the new lang…
chhhee10 Oct 10, 2026
abc2a5a
feat(backfill,config): traced agents only, --agents, --oss
chhhee10 Oct 10, 2026
97a0aac
fix(daemon): a config edit right after a backfill was never applied
chhhee10 Oct 10, 2026
2376736
fix(config): --disconnect no longer sends you to restart the daemon
chhhee10 Oct 10, 2026
f6a346d
fix(policies): show that the pre-pack shim still enforces builtins
chhhee10 Oct 10, 2026
ce94594
feat(cli): flush, migrate, update and uninstall results in the new look
chhhee10 Oct 10, 2026
2347d24
feat(hooks): installs and removals keep the agent selection true
chhhee10 Oct 10, 2026
32c77ed
test(cli): pin the new failure shape of action results
chhhee10 Oct 10, 2026
a96352c
feat(policies): show --releases and the empty picker in the new look
chhhee10 Oct 10, 2026
c5a2c80
fix(config): an unattended re-run keeps a saved empty selection
chhhee10 Oct 10, 2026
30611bf
feat(config): --connect, --disconnect and rename results in the new look
chhhee10 Oct 10, 2026
75d57c4
feat(notices): errors, notices and the one-off screens in the new lan…
chhhee10 Oct 11, 2026
3273d1b
feat(policies): --install and --uninstall results in the new look
chhhee10 Oct 11, 2026
638b297
fix(config): renaming an unconnected machine points at config, not a …
chhhee10 Oct 11, 2026
40188be
feat(jev): setup, test, models and remove results in the new look
chhhee10 Oct 11, 2026
cc26fda
chore(tui): retire the helpers no screen uses any more
chhhee10 Oct 11, 2026
5a96d2c
docs(changelog): one Fixes list, features in reading order
chhhee10 Oct 11, 2026
6355a4d
fix(cli): config and backfill argument errors in the same shape as th…
chhhee10 Oct 11, 2026
82e20b2
test: two tests that failed under load for reasons of their own
chhhee10 Oct 11, 2026
ca8edc3
feat(config): the first-run hints in the new look
chhhee10 Oct 11, 2026
8fb9798
docs(changelog): name the PR, #881
chhhee10 Oct 11, 2026
df1cfbc
chore(deps): clear the advisories OSV-Scanner flags, for the beta
chhhee10 Oct 11, 2026
d696033
test(hooks): two handler tests stop writing untraced notes into the r…
chhhee10 Oct 11, 2026
91d7654
test(hooks): two more suites stop writing into the real ~/.failproofai
chhhee10 Oct 11, 2026
e727018
test(uninstall): pin the options the real command passes removeHooks
chhhee10 Oct 11, 2026
b409fc3
test(tui): restore the logomark shape checks against screenKit().logo()
chhhee10 Oct 11, 2026
a285f2d
test(hooks): an untraced agent's hook event is still evaluated, never…
chhhee10 Oct 11, 2026
cfe1d60
test(e2e): policies --all can now fail on its folding claim
chhhee10 Oct 11, 2026
f58a1c6
test(config): isolate FAILPROOFAI_HOME in the wizard tests, not just …
chhhee10 Oct 11, 2026
b805737
fix(policies): a refused Jev-only pack no longer reads as enforcing
chhhee10 Oct 11, 2026
d9d3c7d
fix(config): an agent traced again starts fresh on every path
chhhee10 Oct 11, 2026
ab1b2e7
test(agents): a removal with no saved list records this machine's agents
chhhee10 Oct 11, 2026
4be7042
fix(config): a bad cloud URL stops only a run that would send a key
chhhee10 Oct 11, 2026
4b65641
fix(config): setup's summary names a pack that failed to load
chhhee10 Oct 11, 2026
bdd27c5
fix(config): the AGENTS step says what will change, not what did
chhhee10 Oct 11, 2026
d90ae2e
docs(config): say what configure_applied sends
chhhee10 Oct 11, 2026
bca58f5
fix(daemon): apply a request that lands mid-tick before the new colle…
chhhee10 Oct 11, 2026
c60e397
test(dashboard): unticking with no saved list records this machine's …
chhhee10 Oct 11, 2026
df13acc
fix(cli): did-you-mean no longer answers --uninstall and unpause with…
chhhee10 Oct 11, 2026
49c896c
fix(cli): a failed update, migrate or flush --wait marks the line tha…
chhhee10 Oct 11, 2026
9621406
fix(cli): config no longer drops --machine-label, and takes --send-tr…
chhhee10 Oct 11, 2026
6a4cacc
chore(cli): drop the --status --verbose promise nothing keeps
chhhee10 Oct 11, 2026
d28bc84
fix(tui): no escape codes in a redirected stderr
chhhee10 Oct 11, 2026
189c233
fix(cli): backfill --dry-run hands over the window it previewed
chhhee10 Oct 11, 2026
2ba1492
fix(tui): never cut a collapsed summary or a help option, and answer …
chhhee10 Oct 11, 2026
3dcf326
fix(cli): the shared policies help says which lane takes -c
chhhee10 Oct 11, 2026
480446f
docs(changelog): agent-list and --machine-label entries match the rev…
chhhee10 Oct 11, 2026
800ca75
fix(daemon): claim a backfill request by rename, so a later write is …
chhhee10 Oct 11, 2026
d15cfb7
chore: bump version to 1.0.11-beta.1
chhhee10 Oct 12, 2026
c6f5b2a
fix(launch): drop Next's "Running next.config took" line under the sc…
chhhee10 Oct 12, 2026
0791714
fix(status): config --status drops the dashboard, today and per-agent…
chhhee10 Oct 12, 2026
aff42d3
chore(deps): quinn-proto 0.11.18 for RUSTSEC-2026-0338 to -0342
chhhee10 Oct 12, 2026
8e4410e
chore(deps): ruzstd 0.9.1 for RUSTSEC-2026-0344
chhhee10 Oct 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,57 @@
# Changelog

## 1.0.11-beta.1 — 2026-10-13

### Features

- New terminal look for the CLI, step one: the palette gains the redesign's label grey, progress-track grey and a red for failures. Descriptions keep the terminal's own colour, and the greys fall back to the dim attribute below 24-bit, so every screen stays readable on light themes (#881)
- Pickers in the new look: an UPPERCASE heading with a live "n of m selected", a `›` cursor and `■ □` boxes, twelve rows before scrolling, plain `a` to toggle all, and the key hints at the foot. The `policies -i` agent menu now uses the shared picker (#881)
- Every `--help` page in the new look, cut to usage, options and examples, with every real flag and its real default. The index opens with three getting-started steps, then lists every command by what it is for. `policies add|remove|show --help` now prints the one policies page (#881)
- Every error in the new look: `✕` and what went wrong, then the fix on its own line with the command in pink, instead of `Error: …`. An unknown word gets "There is no command called 'status'." and "Did you mean failproofai config --status?": words people type (`status`, `login`, `install`, `pause` and more) map to the command that does it, a typo finds the nearest command, and a word close to none gets no guess and points at `failproofai help`. Exit codes are unchanged (#881)
- The notices printed above a command — a daemon that does not match the CLI, the daemon self-heal, a reorganised or newer `~/.failproofai`, and the `--token` warning — are each one state line and one fix line (#881)
- New look for `failproofai policies`, `policies add <pack>` and `policies show <pack>`: every policy is ● on or ○ off, packs are named once at the top, off policies fold into one line per category, and the new `failproofai policies --all` lists every one. At most one line asks for attention, most severe first: a pack that will not load (and so denies what it covers), then "Policies are not enforcing yet." (#881)
- `policies show <owner>/<repo> --releases` and the empty `policies add` picker are drawn in the new look (#881)
- `policies --install` / `--uninstall` results in the new look: one ✓ per agent with where it was written, and the duplicate-scope warning as one ▲ line with its fix. It no longer prints a hard-coded colour code into pipes or under NO_COLOR (#881)
- `failproofai config --status` in the new look: THIS MACHINE (the daemon, pauses), CLOUD and ENFORCEMENT (agents traced, policies on) on one column, now with delivery health from the daemon's own record (last event, backlog, refused batches) and at most one line that needs attention. Per-agent rows, such as one per Hermes profile, are gone: the screen is about the machine. `--pause` and `--resume` confirm with one ✓ sentence, and a pause states the time actually granted, which the 8-hour limit can make shorter than asked (#881)
- New terminal look for the CLI, the dashboard launch screen: bare `failproofai` prints it once the dashboard is actually listening, with its address, the policies that are on, the agents traced and the cloud connection, plus one warning when policies are not enforcing or the dashboard is reachable from other machines. A server that fails to start says why in one line (a taken port is named as such), Next.js's own startup lines are gone, piped output carries no colour codes, and `failproofai audit` hands off to the dashboard without the logomark or the screen (#881)
- `failproofai audit` shows a progress bar per agent and running counts of what would be blocked or warned, redrawn at most every 100 ms in one write per frame; piped or under `NO_COLOR` it prints the finished screen once. Its sign-in, `--schedule`, `--no-schedule` and `--status` screens move to the new look, and audit no longer honours `FORCE_COLOR`, like every other screen (#881)
- `flush`, `migrate`, `update`, `uninstall`, `config --connect`, `--disconnect` and a machine rename print their results in the new look: the header names the command, and a failure opens with ✕ and its fix indented under it (#881)
- `failproofai uninstall` asks one question, `Continue? y/N`, under a plan that says exactly what goes: the hooks and which agents they are in, the failproofaid service, the policy settings in policies-config.json, and `~/.failproofai` with `--purge`. Yes removes all of it, the service included, as `--yes` does; the second "remove the service too?" question is gone (`policies --uninstall` removes only the hooks). `--yes` and the refusal without a terminal are unchanged (#881)
- `failproofai publish` ends on the new done screen: a ✓ per side effect (a commit, a bundle, a new repository), then "Published <id>@<version> with N policies." and the command to install it. A private repository gets a ▲ in the install line's place (#881)
- `failproofai jev status` in the new look: a status row, then provider and model, endpoint, mode, timeout, key and config, the activity block, and the next command last. There is no "last test" row, because nothing records one (#881)
- `jev setup`, `jev test`, `jev models` and `jev remove` results in the new look: the header names the subcommand and its outcome, with kv rows, grey notes, ▲ warnings and one-line next steps (#881)
- A new API-key prompt for `failproofai config`: one masked field, Tab for open source, a saved key shown at once and checked in the background, a spinner while a key is checked, and a refused key kept in the field to retry. A tab or newline inside a paste no longer switches mode or submits halfway (#881)
- `failproofai config` v2: after sudo, one API-key field (Tab for open source; Enter keeps a saved key, which is checked in the background), then which agents failproofai traces. That one remembered list drives hooks, collection and backfill. Every agent is listed: the detected ones are ticked on a first run, a re-run opens on the last answer with newly detected agents ticked, and an upgraded machine opens on what is protected today. Nothing is written until the last question is answered, and the run ends with what was written and whether anything is enforcing. Tab never disconnects a connected machine; `--disconnect` does. An agent traced again starts fresh in the collector instead of resuming old cursors (#881)
- Installing an agent's hooks (`policies --install`, `policies add`, the dashboard's agent panel) now adds it to the agents `failproofai config` traces, at any scope, and removing them at user scope or `--scope all` (`policies --uninstall`, `policies remove all`, the panel) takes it out, each with a one-line note. So the next `failproofai config` neither strips those hooks nor puts them back, and the daemon stops collecting an agent you unhooked. An agent added back starts fresh in the collector, as one re-ticked in `failproofai config` does, instead of resuming its old cursors. With no saved selection, a removal saves one listing this machine's agents (detected, or hooked at user scope) but those removed; project- and local-scope removals, `failproofai config` itself and `failproofai uninstall` leave the selection alone (#881)
- `failproofai backfill` re-sends only the agents failproofai traces, counts sessions with the same readers the audit uses (all twelve agents, where the old survey knew seven), and takes `--agents` for a subset. A name that is not an agent, an untraced agent, or a daemon of another version is refused before anything is written. `config` takes `--oss` and `--agents`, `config --status` counts agents found but not traced, and `harness` says when an agent's extra paths are idle because it is not traced (#881)
- The daemon honours `agents.selected` in `config.json`: a harness that is not selected starts no collector task (its extra capture paths and every Hermes profile included), while hook decisions and the SDK spool are always collected. A change takes effect at the next config poll with no restart; no `agents` key means every harness, as before. An unknown agent id, and an untraced harness that still has extra paths, each get a journal line (#881)
- Backfill requests can name `agents` and a `kind`. `user` (what `failproofai backfill` writes, and what a request without `kind` means) re-sends those agents' files modified since `sinceMs`, now reaching their extra-path stores too; `added` forgets every cursor of the agents `failproofai config` re-adds, Hermes profiles included, and gives them the default 7-day window. A pending request is applied before the collector first starts, and an `added` request older than 10 minutes is dropped (#881)

### Fixes

- `failproofai policies` showed nothing for a machine still on the pre-pack builtins, while those builtins were enforcing. It now says how many under BUILT IN, with the command that moves them into a pack (#881)
- `failproofai config --disconnect` told you to restart the daemon to stop it sending. It stops on its own within a few seconds, because it polls the credential, and now says so (#881)
- A config change that landed while the daemon was restarting its collector after a backfill was recorded as already running and never applied. `failproofai config` re-adding an agent hits exactly that, writing its backfill request and then the selection, so the agent stayed off until some unrelated edit (#881)
- `failproofai backfill 6m` (no `--since`) silently ran the default 30 days. Stray words are refused now, with the option they probably meant (#881)
- `failproofai config --token <key> --machine-label <name>` ran a rename and ignored the key. It now sets the machine up under that name; with `--agents` on a connected machine the name is applied as a rename, and where the machine cannot connect (`--oss`, or no key) it is refused rather than dropped (#881)
- `failproofai config` no longer runs setup with an option it does not know quietly ignored: an unknown option or a stray word is an error (#881)
- `backfill` on an unconnected machine suggested `config --token <key>`, which puts the key in shell history. It points at `failproofai config` (#881)
- `harness add-path` said `harness list` shows what is captured. It shows what is configured; the daemon's log says what it rejected (#881)
- `--cli` in `policies --install`, `--uninstall`, `add` and `remove` named only 8 of the 12 agents and said "Missing value(s)" for a typo; it now says "Not an agent: claud (did you mean claude?)" and lists all 12 (#881)
- The did-you-mean for an unknown command answered `install` with `uninstall`, `status` with `flush` and `-i` with `audit`, and suggested flags in a form that could not be run (#881)
- `failproofai update` without sudo said to re-run `failproofai config` and printed a whole unit file to paste; it now says to run `sudo -v`, then `failproofai update` again. `uninstall` names the commands to run as root when it cannot remove the service (#881)
- `failproofai uninstall` said settings "survive a reinstall" while it reset enabled policies, custom policy paths and policy parameters in policies-config.json; its question now says so (#881)
- `policies remove --scope` with no value left `all` out of the valid scopes, and `policies add|remove` with an unknown flag pointed at `failproofai policy --help` (#881)
- A new backfill request no longer replaces one still waiting for the daemon: requests merge, keeping the wider window, and are written atomically (#881)
- A hook from an agent that `failproofai config` does not trace is logged once per session and evaluated as usual, never allowed because of the selection (#881)
- A backfill's first-sight window now applies only to the agents it names and lasts until a later request for that agent: a scoped backfill no longer widens every other source's window, and an agent added after a backfill starts on 7 days instead of inheriting the backfill's (#881)
- Renaming an unconnected machine suggested `config --connect <url> --token <key>`, a key on the command line; it points at `failproofai config` (#881)
- After every agent's hooks were removed, an unattended `failproofai config` re-run hooked all twelve again; a saved empty selection now stands (#881)

### Dependencies

- Bump `next` to 16.3.8, `sharp` to 0.35.5 and `source-map-js` to 1.2.2, which OSV-Scanner flagged; the dashboard ships `next` and `sharp`. In the SDKs' dev lockfiles: `source-map-js` (TypeScript) and `banks`, `langgraph-sdk`, `multidict` and `pydantic-ai-slim` (Python). `quinn-proto` 0.11.18 (RUSTSEC-2026-0338 to -0342) and `ruzstd` 0.9.1 (RUSTSEC-2026-0344) in `Cargo.lock` (#881)

## 1.0.10 — 2026-10-05

Action needed if you use `instruct` policies with Hermes: an `instruct` no longer stops the call it reminds about. The call runs and the reminder is placed first in its result, so a policy written to prevent an action (for example, a direct API write that should go through an approved script) must become a `deny` before you upgrade. Hermes 0.20.0 is supported again: on 1.0.9 the plugin loaded there with no hooks and every tool call ran unchecked. After upgrading, run `failproofai update` and restart each Hermes gateway profile by name. Collects 1.0.10-beta.0 to beta.1 below.
Expand Down
16 changes: 8 additions & 8 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ resolver = "3"
members = ["crates/*"]

[workspace.package]
version = "1.0.11-beta.0"
version = "1.0.11-beta.1"
edition = "2024"
license-file = "LICENSE"
repository = "https://github.com/FailproofAI/failproofai"
42 changes: 17 additions & 25 deletions __tests__/audit/audit-cli-help.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ describe("audit --help", () => {
// it. Repeating the prefix on every row cost 17 of the 80 columns and was
// what forced the descriptions down to four words a line.
expect(text).toContain("failproofai audit");
expect(text).toContain("Scan your agents' history and open the results");
for (const command of [
"(bare)",
"--schedule [days]",
"--no-schedule",
"--status",
Expand All @@ -66,8 +66,13 @@ describe("audit --help", () => {
expect(plain(render(false))).not.toContain("--scheduled");
});

it("keeps the local-only promise the docs also make", () => {
expect(plain(render(false))).toMatch(/runs on this machine/i);
it("is usage, options and examples, and nothing else", () => {
// Decision D6 of the 2026-10 redesign removed explanatory and privacy
// lines from help pages; the audit's local-only promise went with them.
const headings = plain(render(false))
.split("\n")
.filter((l) => /^[A-Z][A-Z ]+$/.test(l));
expect(headings).toEqual(["USAGE", "OPTIONS", "EXAMPLES"]);
});

it.each([true, false])("aligns and fits 80 columns with color=%s", (color) => {
Expand All @@ -77,27 +82,14 @@ describe("audit --help", () => {
expect(line.length).toBeLessThanOrEqual(80);
}

// Every command row and every continuation line shares one description
// column. Derive it from the first row rather than restating a constant,
// so this fails on drift instead of being updated to match it.
const first = lines.find((l) => l.trim().startsWith("(bare)"));
expect(first).toBeDefined();
const descCol = first!.indexOf("Scan your session history");
expect(descCol).toBeGreaterThan(0);

const continuations = lines.filter(
(l) => l.startsWith(" ".repeat(descCol)) && l.trim().length > 0,
);
// A NON-VACUITY floor, not a layout assertion. The real check is the loop
// below — every continuation starts exactly at `descCol` — and this only
// proves it ran over something. Deliberately well under the count the
// current copy produces: pinning it to the exact number is what made this
// line fail twice for wording changes that improved the screen, once when
// dropping the `failproofai audit` prefix widened the column and again
// when `--email <address>` moved to a row of its own.
expect(continuations.length).toBeGreaterThanOrEqual(2);
for (const line of continuations) {
expect(line[descCol]).not.toBe(" ");
}
// Every option row shares one description column. Measured per row rather
// than against a constant, so this fails on drift instead of being updated
// to match it.
const optionRows = lines.filter((l) => /^ {2}-/.test(l));
// A non-vacuity floor: the loop below must have run over the real rows.
expect(optionRows.length).toBeGreaterThanOrEqual(4);
// The first character after the name's two-space gap.
const columns = new Set(optionRows.map((l) => l.search(/(?<=\S {2,})\S/)));
expect(columns.size).toBe(1);
});
});
3 changes: 2 additions & 1 deletion __tests__/audit/audit-cli-telemetry.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,8 @@ describe("failproofai audit telemetry", () => {
total_hits: 2,
findings: 0,
});
expect(h.launch).toHaveBeenCalledWith("start");
// Audit's hand-off prints its own lines, so the dashboard starts with no launch screen.
expect(h.launch).toHaveBeenCalledWith("start", { screen: false });
expect(exitInfo).toBeNull(); // happy path never exits — launch() keeps the process alive
});

Expand Down
Loading
Loading