#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
| level | meaning |
|---|---|
observe | read, analyse, report |
recommend | observe + every write creates an Approval (202); nothing is executed |
execute | recommend + 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
| grant | effect |
|---|---|
finances:observe@business:THARAN | can read summaries, forecasts and context for THARAN |
ads:execute@business:THARAN · max_change_pct_per_day: 10 · max_amount_minor_per_action: 50000 | may change THARAN ad budgets up to ±10 % a day and 500 PLN per action; larger changes become Approvals |
ads:recommend@business:Klima | may propose ad changes for Klima; every one waits for the owner |
subscriptions:observe@all | can read subscriptions and capacity everywhere except Personal |
| (no grant) Personal, Clothing | 403 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>.
| level | znaczenie |
|---|---|
observe | odczyt, analiza, raport |
recommend | observe + write tworzy Approval (202), nic nie jest wykonywane |
execute | recommend + 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
pendingApproval innego agenta →409 state_conflictzdetails.conflict {approval_id, agent_id, action}(AuditEntrydenied,AuthzDecision.deny.code+=state_conflict). Check konfliktu i INSERT Approval wykonywane w jednej transakcji (authorize dostajetx), ż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 zamount_minorw oknie; porejected/expired/cancelledkwota wraca do puli;approvedprzechodzi z „pending” do „wykonane” bez podwójnego liczenia.limit_checkedw AuditEntry rozbijausagenaexecuted_minoripending_minor. Odmowalimit_exceeded(0.6.1): AuditEntrydeniedzlimit_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 auditdenied).personalnigdy nie wynika zall, wymaga jawnego grantu@personal. - Grant na business obejmuje jego projekty. Grant wygasły (
expires_at) = brak grantu. ads:executelimitmax_change_pct_per_day(np. 10 = ±10%).- Wymagany scope: czytanie podsumowań
finances:observe;create_expense→expenses;create_recurring_expense→subscriptions+expenses;create_planned_expense→planned_expenses;reserve_budget→budget_reserve;allocate_shared_expense→allocations;propose_ad_budget_change→ads(≥recommend);create_decision→decisions;get_decision_outcomes,get_decision_review→decisions(observe);simulate_scenario→finances+forecast(observe);request_data→dowolny aktywny agent (jakrequest_permission);get_goals,get_onboarding→goals(observe; onboarding = własny passport, zawsze dozwolone);propose_goal→goals(≥ recommend, wynik zawsze Approval).