atmon docs

REFERENCE/API/RULES.MD

RulesService

Read the rules this project runs under, in the same words the console shows them in, and propose a change to them. Proposing writes nothing: it files a proposal that lands in the project's inbox, and a person approves or declines it there. That boundary is the point rather than a limitation, and it is the same one the approval gate draws around a parked call.

Every call is a POST to https://api.atmon.ai/automaton.v1.RulesService/<Call> with a JSON body, and authenticates with Authorization: Bearer <your project key>. Field names in JSON are lowerCamelCase, so the field written tool_slug below is toolSlug on the wire. How to call the API has the whole convention.

Calls

CallRequestResponseSummary
GetRulesGetRulesRequestGetRulesResponseReads the project's rules in plain words, grouped by what each one governs.
ProposeRulesChangeProposeRulesChangeRequestProposeRulesChangeResponseFiles a proposed change to the rules.
GetRuleProposalGetRuleProposalRequestGetRuleProposalResponseReads one filed proposal in any state, so a caller can wait for the decision and report it.

GetRules

Reads the project's rules in plain words, grouped by what each one governs. An empty answer at version 0 means no rules have ever been written.

Request GetRulesRequest, response GetRulesResponse.

POST /automaton.v1.RulesService/GetRules HTTP/1.1
Host: api.atmon.ai
Authorization: Bearer amk_your_project_key
Content-Type: application/json

{}

The response:

{
  "version": 0,
  "rules": [{
    "area": "...",
    "text": "..."
  }]
}

ProposeRulesChange

Files a proposed change to the rules. It writes no policy: the answer is a proposal id in the PENDING state, and a person approves or declines it in the console. Refiling an identical pending proposal answers with the one already filed. A project may file a small number of proposals per hour; past that the call is refused with resource_exhausted.

Request ProposeRulesChangeRequest, response ProposeRulesChangeResponse.

POST /automaton.v1.RulesService/ProposeRulesChange HTTP/1.1
Host: api.atmon.ai
Authorization: Bearer amk_your_project_key
Content-Type: application/json

{
  "changes": [{
    "setSpendCeiling": { ... },
    "requireApproval": { ... },
    "setAllowedTools": { ... }
  }],
  "reason": "..."
}

The response:

{
  "proposal": {
    "id": "...",
    "changes": [{ ... }],
    "reason": "...",
    "effects": ["..."],
    "state": "RULE_PROPOSAL_STATE_PENDING",
    "note": "...",
    "createdAt": "2026-01-31T09:15:00Z",
    "decidedAt": "2026-01-31T09:15:00Z",
    "appliedPolicyVersion": 0
  },
  "deduplicated": true
}

GetRuleProposal

Reads one filed proposal in any state, so a caller can wait for the decision and report it. A declined proposal reads as declined with whatever the decider wrote; do not file it again.

Request GetRuleProposalRequest, response GetRuleProposalResponse.

POST /automaton.v1.RulesService/GetRuleProposal HTTP/1.1
Host: api.atmon.ai
Authorization: Bearer amk_your_project_key
Content-Type: application/json

{
  "id": "..."
}

The response:

{
  "proposal": {
    "id": "...",
    "changes": [{ ... }],
    "reason": "...",
    "effects": ["..."],
    "state": "RULE_PROPOSAL_STATE_PENDING",
    "note": "...",
    "createdAt": "2026-01-31T09:15:00Z",
    "decidedAt": "2026-01-31T09:15:00Z",
    "appliedPolicyVersion": 0
  }
}

Messages

GetRuleProposalRequest

FieldType#Notes
idstring1

GetRuleProposalResponse

FieldType#Notes
proposalRuleProposal1

GetRulesRequest

No fields. The call takes its scope from the authenticated project.

GetRulesResponse

FieldType#Notes
versionint641version is the policy document's version. Zero means the project has never written rules, and rules is then empty: nothing is capped, nothing is gated, and everything in the catalog is allowed.
rulesrepeated RuleStatement2

ProposeRulesChangeRequest

FieldType#Notes
changesrepeated RulesChange1
reasonstring2

ProposeRulesChangeResponse

FieldType#Notes
proposalRuleProposal1
deduplicatedbool2deduplicated is true when an identical proposal was already pending and this call answered with that one instead of filing a second. Refiling the same change is not an error and it does not make a second row.

RequireApproval

RequireApproval proposes adding calls to the approval gate. It only ever adds: a proposal cannot take a tool out of the gate, because loosening the gate through the surface an agent writes to would make the gate advisory. Removing one is a console edit by a person.

FieldType#Notes
tool_slugsrepeated string1tool_slugs are catalog-wide slugs, "github.delete_repo". Requiring approval for one app's destructive actions means listing that app's destructive tools; the document has no per-app rule, and naming the tools is what it can actually enforce.
include_destructive_classbool2include_destructive_class gates every tool the catalog classes destructive, in every app. It can be set true and never false.

RuleProposal

RuleProposal is one filed change and everything decided about it.

FieldType#Notes
idstring1
changesrepeated RulesChange2
reasonstring3reason is what the proposer said the change is for, in its own words. It is shown to whoever decides, so it is the argument rather than a label.
effectsrepeated string4effects is the change in plain words, one line per change, the same sentences the console renders beside the decision.
stateRuleProposalState5
notestring6note is what whoever decided it said. On a decline it is the reason not to file the same thing again.
created_atgoogle.protobuf.Timestamp7
decided_atgoogle.protobuf.Timestamp8
applied_policy_versionint649applied_policy_version is the document version the approval wrote. Zero while the proposal is pending and on one that was declined.

RuleStatement

Rules as an agent reads them, and proposes changes to.

The document above is written for the code that enforces it. An assistant asked "what are the rules here" needs the same facts in the language the person who wrote them used, and an assistant that spots a missing ceiling needs somewhere to say so. Neither of those is a policy write: the asker is never the approver, so a change an agent drafts becomes a proposal that lands beside the approvals in the project's inbox, and a person decides it.

RuleStatement is one rule in force, written the way the console shows it rather than the way the document stores it.

FieldType#Notes
areastring1area groups the statement, one of: spending, approvals, tools, pace, data, retention, visibility, connections.
textstring2

RulesChange

RulesChange is one edit to the project's rules. Exactly one field is set, and a change carrying none or more than one is refused when it is filed rather than stored as something nobody can apply. A proposal that wants two edits carries two of these.

Three fields rather than a oneof: on the JSON wire the two are written identically, and the rule is enforced at the desk either way, with a message naming the field and what to send instead.

FieldType#Notes
set_spend_ceilingSetSpendCeiling1
require_approvalRequireApproval2
set_allowed_toolsSetAllowedTools3

SetAllowedTools

SetAllowedTools proposes narrowing what may run to a named list. An empty list on either field leaves that list alone; the document's own convention is that an empty allow list allows everything, so clearing one is a loosening and is not proposable here.

FieldType#Notes
allowed_toolsrepeated string1catalog-wide slugs
allowed_toolkitsrepeated string2

SetSpendCeiling

SetSpendCeiling proposes one ceiling. A ceiling for the same scope, window, entity and toolkit replaces the one in force; a new combination is added. A proposal setting every dimension to zero removes the ceiling, which is a loosening and reads that way in the proposal's own words.

FieldType#Notes
scopeBudgetScope1
entity_idstring2BUDGET_SCOPE_ENTITY only
windowBudgetWindow3
max_model_micro_usdint644
max_actionsint645
max_provider_callsint646
toolkit_slugstring7max_provider_calls only

Enums

BudgetScope

BudgetScope is whose spending a ceiling counts, following VelocityLimit's scopes minus the tool scope: money is spent by a project or by one of its entities, and a per-tool ceiling would be a quota, which max_provider_calls already expresses.

Value#Meaning
BUDGET_SCOPE_UNSPECIFIED0
BUDGET_SCOPE_PROJECT1
BUDGET_SCOPE_ENTITY2

BudgetWindow

BudgetWindow is the period a ceiling applies over, evaluated in UTC. TOTAL never resets, so only raising the ceiling releases what it parked; DAILY and MONTHLY reset at the UTC boundary and release a parked job with no operator action.

Value#Meaning
BUDGET_WINDOW_UNSPECIFIED0
BUDGET_WINDOW_TOTAL1
BUDGET_WINDOW_DAILY2
BUDGET_WINDOW_MONTHLY3

RuleProposalState

Value#Meaning
RULE_PROPOSAL_STATE_UNSPECIFIED0
RULE_PROPOSAL_STATE_PENDING1waiting on a person
RULE_PROPOSAL_STATE_APPROVED2applied to the document
RULE_PROPOSAL_STATE_DECLINED3decided against, and it stays on the record