Skip to content

feat(gain-web): Tirith trust manager pane (write-side, depends #162) #176

Description

@thehoff

Background

ContextCrawler's Tirith gate ([#33 / #32] context) blocks commands at the loopback hook layer, then writes downgrade events to `~/Library/Application Support/contextcrawler/downgrades.jsonl`. When the gate fires on a legitimate command, the escape hatch is `tirith trust add --scope repo --rule <rule_id>` from the shell.

The dashboard's Security pane (#171) shows every downgrade. It doesn't let you act on them.

Problem

A real operational flow looks like:

  1. Hoff runs `agy --add-dir ...` for peer review.
  2. Tirith gate flags `agy` as an editable / path / URL token because the prompt body includes `https://` examples.
  3. Block lands in the Security pane.
  4. Hoff has to flip to a shell, recall the rule_id, run `tirith trust add`, re-run the command.

The roundtrip breaks the dashboard's promise of "glanceable status" — every action requires context-switching back to terminal.

Proposed scope

First write-side feature on the dashboard

This is the first feature that mutates state from the loopback UI. Pattern to establish for later write features (#TBD #175 council annotations, etc.).

New endpoints

```
GET /api/security/trust → list current entries from tirith trust list --json
POST /api/security/trust → add an entry (body: {host, scope, rule_id})
DELETE /api/security/trust/ → remove
```

All three shell out to the `tirith trust` CLI — never poke Tirith's config files directly (config schema is upstream-owned).

Frontend behaviour

  • New "Trust manager" sub-pane under Security
  • Each recent downgrade row gets an inline [Trust this rule] button
    • Click → modal showing the suggested `{host, scope, rule_id}` populated from the downgrade event
    • Explicit confirm required — two-step interaction, not one-click (this is a security control we're loosening)
    • Modal also shows the blast radius: "this will allow any command matching from in "
  • Existing entries listed in a table with [Revoke] button per row

Loopback-only contract preserved

Server still binds 127.0.0.1 only. No CSRF protection needed (loopback + no shared cookies). But:

  • Log every write action to `~/Library/Application Support/contextcrawler/trust_actions.jsonl` (timestamp, action, payload) — gives an audit trail mirroring the gate's own logs.
  • Display the most recent 10 trust changes in the pane so the user always sees what was last modified.

Out of scope (v1)

  • Editing rule definitions (only add/remove existing rules).
  • Bulk operations.
  • Trust suggestions / ML-driven recommendations.
  • Anything that talks to a remote Tirith server.

Effort

M. ~1 week.

  • 3 endpoints + tests (incl. CLI subprocess wrapping with proper error surfacing): 2 days
  • Frontend pane + modal + confirm UX: 2 days
  • Audit log + display: 1 day
  • Doc + screenshot + peer-review pair: 1 day

Why now

Single-model pick (Claude only in 3-way brainstorm 2026-05-25), but the operational gap is real. Closes the loop between "I see the block in the dashboard" and "I can act on it without flipping back to shell". Becomes the pattern for all future write-side features.

Dependencies

Risk

Loosening the gate from the UI is a security-relevant action. The two-step confirmation + audit-log + blast-radius display are non-negotiable parts of v1; do not ship the endpoint without them.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions