CoreLayer Docs
Core Concepts

Permission Guard

Risk-based execution control with persisted approvals and a complete audit trail.

The Permission Guard sits between the model and every side effect. It classifies a call by the risk declared on the tool, applies policy, and — when the answer is "ask" — suspends the work instead of guessing.

Risk model

Four levels, each mapping to an action:

RiskDefault actionTypical tools
lowautoRead, query, discover, code skeleton
mediumnotifyCreate or update a task, add an article, save a review
highconfirmDelete, dispatch an agent, run a task graph
criticaldenyBlocked unless an explicit grant exists

Per-app overrides tighten or loosen a single level (evaluated when a guard is constructed with them; the daemon currently runs with the defaults):

appPermissions: {
  "some-app": { write: false, execute: false }
}
// medium → confirm (write: false)
// high   → deny    (write: false)
// critical → deny  (execute: false)

Voice execution is stricter: only read-only actions are auto-allowed, everything else requires confirmation.

Why risk is declared, not inferred

Inference from tool names and arguments has failed in a predictable direction. dispatch_agent and run_task_graph contain no risky-sounding word but spawn runs that write files and execute commands; name inference rated them low, which the default policy auto-approves. The registry therefore requires an explicit risk level for every native tool.

Approval flow

Tool call or executor permission request
  → risk read from the tool definition
  → policy: auto / notify / confirm / deny
  → confirm: persist an approval request
      - action digest (what exactly will run)
      - risk, scope, expiry
  → suspend the run
  → UI decision: approve / deny / remember
  → resume service continues or fails the run
  → audit entry written either way

Because approvals are persisted, a pending decision is not lost when the daemon restarts. POST /api/approvals/expire-stale closes requests that nobody answered, and batch endpoints exist for queues that accumulated during unattended work.

Permission memories

"Remember" records a decision against the action digest, so the identical action is not asked again. It is scoped: a different path, command, or parameter set is a different digest and is asked again.

Audit trail

Every decision is written with actor, action, risk, decision, and result. Entries are queryable through GET /api/audit with actor, action, riskLevel, since, limit, and offset filters.

The audit log is separate from the event log: the audit log answers "what was allowed or denied", the event log answers "what happened during this run" (GET /api/events).

Inspecting state

  • GET /api/approvals — pending and recent approvals
  • GET /api/approvals/:id — one request
  • POST /api/approvals/:id/approve / deny / remember
  • GET /api/audit?riskLevel=high — high-risk decisions

Next Steps

On this page