#Permissions: Agent Passport

Every agent has a passport: a list of grants. A grant is scope × level × resource × limits, written in short form as ads:execute@business:<id>. Default deny, anything not granted returns 403 scope_denied and lands in the audit log.

#Scopes

finances, subscriptions, ads, forecast, expenses, planned_expenses, budget_reserve, allocations, goals, decisions.

#Levels

levelmeaning
observeread, analyse, report
recommendobserve + every write creates an Approval (202); nothing is executed
executerecommend + writes execute immediately within limits; above the per-action limit → Approval; above the daily/monthly limit → 403 limit_exceeded

#Resources

all (all businesses and their projects: never Personal), business:<id> (includes its projects), project:<id>, personal (needs an explicit grant). An expired grant (expires_at) is no grant.

#Limits

{
  "max_amount_minor_per_action": 50000,
  "max_amount_minor_per_day": 200000,
  "max_amount_minor_per_month": 1500000,
  "max_change_pct_per_day": 10,
  "currency": "PLN"
}

Amounts are compared in the limit's currency at the current rate; the audit entry stores the original amount, the converted one and the rate used.

#Example: Marketing Agent

granteffect
finances:observe@business:THARANcan read summaries, forecasts and context for THARAN
ads:execute@business:THARAN · max_change_pct_per_day: 10 · max_amount_minor_per_action: 50000may change THARAN ad budgets up to ±10 % a day and 500 PLN per action; larger changes become Approvals
ads:recommend@business:Klimamay propose ad changes for Klima; every one waits for the owner
subscriptions:observe@allcan read subscriptions and capacity everywhere except Personal
(no grant) Personal, Clothing403 scope_denied, and the denial is audited

#Asking for more

Use request_permission (MCP) or POST /v1/permission-requests: it creates an Approval with action = "grant_scope". Explain in reason which analysis is blocked without it. The owner grants, rejects or modifies it in the Approval Center.

#Which scope does a tool need?

See the tools reference, each tool lists its required scope, and the table below is generated from the contract.

Source: KONTRAKT §10 (scopes and levels) (Polish, verbatim from the contract)

#10. Scopes i poziomy autonomii (spec §22-23)

Scopes (string): finances, subscriptions, ads, forecast, expenses, planned_expenses, budget_reserve, allocations, goals, decisions. Grant = scope × level × resource (all | business:<id> | project:<id> | personal) × limits. Zapis skrótowy: ads:execute@business:<id>.

levelznaczenie
observeodczyt, analiza, raport
recommendobserve + write tworzy Approval (202), nic nie jest wykonywane
executerecommend + write wykonywany od razu w limitach; ponad limit „per action" → Approval; ponad limit dzienny/miesięczny → 403 limit_exceeded
  • Konflikt zasobu między agentami (0.7.1, spec §31): write/propozycja dotycząca tego samego zasobu (kampania, subskrypcja, rezerwacja), dla którego istnieje pending Approval innego agenta → 409 state_conflict z details.conflict {approval_id, agent_id, action} (AuditEntry denied, AuthzDecision.deny.code += state_conflict). Check konfliktu i INSERT Approval wykonywane w jednej transakcji (authorize dostaje tx), żeby dwie równoległe propozycje nie przeszły obie.
  • Limity dzienne/miesięczne liczą także kwoty OCZEKUJĄCYCH Approval agenta (status=pending), ochrona przed podwójnym budżetowaniem (spec §31): usage = Σ wykonane akcje w oknie + Σ pending Approval z amount_minor w oknie; po rejected/expired/cancelled kwota wraca do puli; approved przechodzi z „pending” do „wykonane” bez podwójnego liczenia. limit_checked w AuditEntry rozbija usage na executed_minor i pending_minor. Odmowa limit_exceeded (0.6.1): AuditEntry denied z limit_checked[] (jeden wpis per sprawdzony limit: {limit_key, limit_minor|pct, usage_minor, attempted_minor, currency, window}).
  • Samoobsługowe dla każdego aktywnego agenta (zamierzone, 0.8.1): GET /me, GET /agents/me, GET /agents/:id (własny), GET /agents/:id/passport (własny), POST /permission-requests, POST /data-requests, GET /approvals (własne): nie wymagają grantu, bo agent musi móc poznać własne uprawnienia i poprosić o więcej; zawsze audytowane.
  • Default deny. Brak grantu = 403 scope_denied (z audit denied). personal nigdy nie wynika z all, wymaga jawnego grantu @personal.
  • Grant na business obejmuje jego projekty. Grant wygasły (expires_at) = brak grantu.
  • ads:execute limit max_change_pct_per_day (np. 10 = ±10%).
  • Wymagany scope: czytanie podsumowań finances:observe; create_expenseexpenses; create_recurring_expensesubscriptions+expenses; create_planned_expenseplanned_expenses; reserve_budgetbudget_reserve; allocate_shared_expenseallocations; propose_ad_budget_changeads (≥recommend); create_decisiondecisions; get_decision_outcomes, get_decision_reviewdecisions (observe); simulate_scenariofinances+forecast (observe); request_data→dowolny aktywny agent (jak request_permission); get_goals, get_onboardinggoals (observe; onboarding = własny passport, zawsze dozwolone); propose_goalgoals (≥ recommend, wynik zawsze Approval).