Skip to content

chore: approval gate: command-class + autonomy-tier policy, store-persisted, fail-closed (Phases 2+4) - #768

Merged
getappz merged 2 commits into
masterfrom
task/197-approval-gate-command-class-autonomy-tie
Sep 17, 2026
Merged

getappz merged 2 commits into
masterfrom
task/197-approval-gate-command-class-autonomy-tie

Conversation

@getappz

@getappz getappz commented Sep 17, 2026

Copy link
Copy Markdown
Owner

Committed on task/197-approval-gate-command-class-autonomy-tie (not pushed).

Status: Implemented the safety core for item #197 (child of epic #131, Phase 2/4 — approval flow + policy engine), adapting openhuman's approval-gate design (refs/openhuman/src/openhuman/approval/).

What landed:

  • agentflare-store/src/approval.rs — restart-safe pending_approvals + allowlist tables (own module, using refactor(mcp): split item_inner's dispatch arms into src/mcp_server/item.rs #187's Store engine, not kv), race-safe decide() (WHERE decided_at IS NULL), lazy TTL expiry, write-once execution audit rows.
  • New agentflare-approval crate: classifier (fail-closed Read/Write/Network/Install/Destructive, handles pipes/&&/;, $(...)/backtick substitution, sudo, env prefixes — highest class wins), policy (tier matrix: ReadOnly/Supervised/Full → Allow/Prompt/Block), redact (home-path scrubbing, secret masking, JSON redaction), gate (ApprovalGate: park on oneshot + TTL, first-wins race between decide() callers, re-reads the store before denying on timeout, persists "approve always" onto the allowlist).

Tests: 148 unit tests, all passing — classifier checklist cases (incl. piped commands), tier matrix, first-wins decide race, TTL fail-closed deny, restart persistence (reopened SQLite file), redaction (paths/secrets/JSON). cargo clippy clean (-A unsafe_code -A clippy::pedantic per this repo's gate command), cargo fmt clean, full cargo check --workspace clean (only pre-existing unrelated warnings elsewhere).

Not done / explicit scope gap: the actual channel-card delivery wired to flare-channels (#131 Phase 1/2) and a terminal-prompt call site in the CLI's real tool-execution path aren't wired up yet — this lands the tested library both of those can call into (ApprovalGate::intercept / decide), same pattern flare-channels itself shipped as "behavior-free" infra. Worth a follow-up item before this is load-bearing in the live binary.


Opened by claude-code on flared:c997d745ae66 for item #197 via agentflare.

Adds the safety core for #131's human-in-the-loop approval flow:

- agentflare-store/src/approval.rs: restart-safe pending_approvals +
  allowlist tables, race-safe decide() (WHERE decided_at IS NULL),
  lazy TTL expiry, write-once execution audit rows.
- agentflare-approval crate:
  - classifier: fail-closed command -> Read/Write/Network/Install/
    Destructive, handling piped/compound commands, command
    substitution, sudo, and env-var prefixes (highest class wins).
  - policy: autonomy tier (ReadOnly/Supervised/Full) -> Allow/Prompt/
    Block matrix.
  - redact: home-path scrubbing, secret masking, and JSON field
    redaction for anything persisted or broadcast.
  - gate: ApprovalGate parks a call on a oneshot + TTL, races the
    channel/terminal surfaces to decide() with a re-read-before-deny
    timeout path, and persists an "approve always" grant onto the
    allowlist.

148 new/updated unit tests covering the classifier's checklist cases
(including piped commands), the tier matrix, the first-wins decide
race, TTL fail-closed deny, restart persistence, and redaction.

Not yet wired: an actual channel-card delivery integration with
flare-channels and a CLI-side terminal prompt call site — this lands
the tested library the epic's Phase 1/2 channel work and the binary's
tool-execution path can both call into.

Agentflare-Agent: claude-code
Agentflare-Branch: task/197-approval-gate-command-class-autonomy-tie
Agentflare-Item: 197
Agentflare-Session: 212ebfd4-9974-4efd-9daa-bbe97d6f8c04
@coderabbitai

coderabbitai Bot commented Sep 17, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 40 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available. Your 60 included PR review attempts over the past 7 days set your current allowance at 1 review per hour.

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Essentials

Run ID: 46062cbf-45db-4428-9deb-e8725e4ff73b

📥 Commits

Reviewing files that changed from the base of the PR and between fd385be and c43f2dc.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (11)
  • Cargo.toml
  • crates/agentflare-approval/Cargo.toml
  • crates/agentflare-approval/src/classifier.rs
  • crates/agentflare-approval/src/gate.rs
  • crates/agentflare-approval/src/lib.rs
  • crates/agentflare-approval/src/policy.rs
  • crates/agentflare-approval/src/redact.rs
  • crates/agentflare-approval/src/types.rs
  • crates/agentflare-store/src/approval.rs
  • crates/agentflare-store/src/lib.rs
  • crates/agentflare-store/src/migrations.rs

Comment @coderabbitai help to get the list of available commands.

@getappz
getappz merged commit 5c35298 into master Sep 17, 2026
17 checks passed
@getappz
getappz deleted the task/197-approval-gate-command-class-autonomy-tie branch September 17, 2026 18:06
getappz added a commit that referenced this pull request Oct 21, 2026
…oject archive/unarchive (#768) (#943)

`project_dir::list` was a bare SELECT, so a soft-deleted project's folder
row (only a hard delete cascades) and an archived project's (nothing read
`archived_at`) were swept every discovery tick. 29 stale Temp\.tmp*
registrations flooded `agentflare daemon logs` with "folder does not
exist" every tick.

- `project_dir::list` joins `projects` and skips deleted/archived ones;
  `list_all` keeps the raw table for folder/item -> project lookups
  (`flare doctor`, item controls).
- `project::delete` also removes the `project_dirs` row, in one transaction.
- `project::archive` / `unarchive`, exposed as `agentflare project
  archive|unarchive <name|id>` and MCP `project action=archive|unarchive`
  (`project` = name or UUID, default: this repo's project). Unarchive needs
  no re-registration.
- The missing-folder line is logged once per project per daemon session,
  and again only after the folder has come back and gone missing again.

Agentflare-Agent: claude-code
Agentflare-Branch: task/768-project-dirs-survives-project-soft-delet
Agentflare-Item: 768
Agentflare-Session: e4957d62-33fe-4989-9971-ea9f52c41af2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant