<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Arfinex</title>
    <description>The latest articles on DEV Community by Arfinex (@arfinex).</description>
    <link>https://dev.to/arfinex</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4199905%2F140c2f42-0222-4782-9690-9bc90f7873f9.png</url>
      <title>DEV Community: Arfinex</title>
      <link>https://dev.to/arfinex</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/arfinex"/>
    <language>en</language>
    <item>
      <title>Authority levels for finance AI agents: a small policy model you can test</title>
      <dc:creator>Arfinex</dc:creator>
      <pubDate>Wed, 04 Nov 2026 07:20:07 +0000</pubDate>
      <link>https://dev.to/arfinex/authority-levels-for-finance-ai-agents-a-small-policy-model-you-can-test-5ch1</link>
      <guid>https://dev.to/arfinex/authority-levels-for-finance-ai-agents-a-small-policy-model-you-can-test-5ch1</guid>
      <description>&lt;p&gt;Most discussions about AI agents in finance stop at "keep a human in the loop". That sentence is true and almost useless to an engineer, because it does not say which loop, which human, or what happens when the human is not there. This post is about turning it into something you can write down, review and test.&lt;/p&gt;

&lt;h2&gt;
  
  
  Four actions, four levels of authority
&lt;/h2&gt;

&lt;p&gt;Start by listing what an agent can actually do. In a finance system, the list is short:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Notify&lt;/strong&gt;: send an internal reminder or flag an exception.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Draft&lt;/strong&gt;: build a journal entry, a payment proposal or a report, without posting it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Post&lt;/strong&gt;: record a final, balanced entry in the ledger.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pay&lt;/strong&gt;: initiate an outgoing payment.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These are not the same risk. A wrong reminder costs a minute. A wrong posted entry changes a report someone already used. A wrong payment may not come back. So each level gets its own rule: which role may allow it, up to what amount, whether a second approval is needed, and what stops it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Policy as data, not as prompt text
&lt;/h2&gt;

&lt;p&gt;The tempting shortcut is to put the rules in the agent's prompt ("never pay more than 5,000 without approval"). Prompts are not a control. They are not versioned with the books, they cannot be audited, and a model can misread them. Put the policy in data, and let deterministic code enforce it after the model has proposed something.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;notify&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;draft&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;post&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pay&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Rule&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;level&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Level&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;allowedRoles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nl"&gt;maxAmount&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;          &lt;span class="c1"&gt;// in reporting currency&lt;/span&gt;
  &lt;span class="nl"&gt;secondApproval&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;stopIf&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;StopCondition&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;StopCondition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;destination_account_changed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;over_limit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;missing_document&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;unusual_amount_change&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sources_disagree&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;policy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Rule&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;level&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;notify&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;allowedRoles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;agent&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="na"&gt;secondApproval&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;stopIf&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;level&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;draft&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="na"&gt;allowedRoles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;agent&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="na"&gt;secondApproval&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;stopIf&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sources_disagree&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;level&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;post&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="na"&gt;allowedRoles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;accountant&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;controller&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="na"&gt;maxAmount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;secondApproval&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;stopIf&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;missing_document&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;unusual_amount_change&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sources_disagree&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;level&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pay&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="na"&gt;allowedRoles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;treasurer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="na"&gt;maxAmount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;secondApproval&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;stopIf&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;destination_account_changed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;over_limit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;missing_document&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The numbers above are examples. The point is the shape: every action the agent proposes is checked against a rule it did not write.&lt;/p&gt;

&lt;h2&gt;
  
  
  The check happens outside the model
&lt;/h2&gt;

&lt;p&gt;The agent proposes. A plain function decides.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;decide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Proposal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;rule&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Rule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;run&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;wait&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;stop&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;rule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stopIf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;detects&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;stop&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;                                   &lt;span class="c1"&gt;// a person must look&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;maxAmount&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;rule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;maxAmount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;wait&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;rule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;allowedRoles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instructedBy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;role&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;wait&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;secondApproval&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hasSecondApprover&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;wait&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;run&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three outcomes matter. &lt;strong&gt;Run&lt;/strong&gt; means the action is inside what the organization already approved. &lt;strong&gt;Wait&lt;/strong&gt; means it needs a named person. &lt;strong&gt;Stop&lt;/strong&gt; means something looks wrong and nobody should approve it without reading the evidence first.&lt;/p&gt;

&lt;p&gt;Because &lt;code&gt;decide&lt;/code&gt; is ordinary code, you can unit-test it: a payment to a changed bank account must always return &lt;code&gt;stop&lt;/code&gt;, whatever the model said in its explanation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep facts, inferences, suggestions and decisions apart
&lt;/h2&gt;

&lt;p&gt;When an agent explains itself, it mixes four kinds of statement:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a &lt;strong&gt;fact&lt;/strong&gt; that came straight from a source (a bank line, an invoice),&lt;/li&gt;
&lt;li&gt;an &lt;strong&gt;inference&lt;/strong&gt; made by combining data,&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;suggestion&lt;/strong&gt; for the next action,&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;decision&lt;/strong&gt; that only an authorized person can make.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Store them as separate fields, not one paragraph. A reviewer can then see at a glance that "this invoice is probably a duplicate" is an inference, and that the decision field is still empty.&lt;/p&gt;

&lt;h2&gt;
  
  
  Log every run so it can be replayed
&lt;/h2&gt;

&lt;p&gt;For each run, record the time, the sources read, the version of the rule used and the result. If a recurring workflow runs monthly, a change in the rule creates a new version instead of silently changing old results. That is what lets an auditor ask "why was this posted?" months later and get an answer that is not "the model thought so".&lt;/p&gt;

&lt;h2&gt;
  
  
  Arithmetic is not the model's job
&lt;/h2&gt;

&lt;p&gt;Let the model read documents, extract lines and propose matches. Let deterministic code do the calculation, the debit-equals-credit check and the final posting. Balances should be the sum of entries, and corrections should be reversing entries, never edits.&lt;/p&gt;

&lt;p&gt;If you are designing something similar, the one test worth writing first is the boring one: feed your decision function a payment whose destination account changed yesterday, and make sure it stops.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This article was written with the help of AI and reviewed for accuracy before publishing.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>fintech</category>
      <category>accounting</category>
    </item>
    <item>
      <title>Can AI Post Journal Entries? Where Agents Stop and Approval Starts</title>
      <dc:creator>Arfinex</dc:creator>
      <pubDate>Wed, 28 Oct 2026 07:26:16 +0000</pubDate>
      <link>https://dev.to/arfinex/can-ai-post-journal-entries-where-agents-stop-and-approval-starts-3f7</link>
      <guid>https://dev.to/arfinex/can-ai-post-journal-entries-where-agents-stop-and-approval-starts-3f7</guid>
      <description>&lt;p&gt;&lt;em&gt;A plain answer for CFOs, controllers and finance managers of multi-entity organizations&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Can AI post journal entries? It can prepare them, but in a well-controlled finance team it should not post them on its own. In Arfinex, AI agents read, compare, find differences and draft a proposal with its sources; one person records the entry, a different person approves it, and every figure comes from the ledger.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why "can AI post journal entries" is the wrong first question
&lt;/h2&gt;

&lt;p&gt;Most finance teams are not asking whether a model is clever enough to write a debit and a credit. They are asking who is accountable when that entry is wrong. An auditor will ask the same thing: who proposed it, which documents support it, who approved it and when.&lt;/p&gt;

&lt;p&gt;So the useful question is: which steps can an AI agent take, and where does human approval start?&lt;/p&gt;

&lt;h2&gt;
  
  
  What an AI agent can do with journal entries
&lt;/h2&gt;

&lt;p&gt;In Arfinex, each agent has a separate role and a written authority table. Observing, analysing, proposing and drafting are allowed. In practice, that means an agent can:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Read bank and payment sources, the ledger and open items after the nightly close.&lt;/li&gt;
&lt;li&gt;Compare them and flag a difference, such as an unmatched receipt or an unbalanced balance.&lt;/li&gt;
&lt;li&gt;Draft a proposed correction, labelled as a proposal, with links to the entries and documents it relies on.&lt;/li&gt;
&lt;li&gt;Explain a movement in plain words for the morning brief, citing its sources.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each finding comes with its evidence, its source and a confidence level, and fact is kept apart from inference.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the agent stops
&lt;/h2&gt;

&lt;p&gt;Execution needs permission, and anything that touches money needs management approval. Anything that would change the books goes through the normal recording and approval path:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A person records the entry. The agent's draft is a starting point, not a posting.&lt;/li&gt;
&lt;li&gt;A different person approves it. Recorder and approver are never the same person.&lt;/li&gt;
&lt;li&gt;An unbalanced entry never becomes final, and re-entry with the same reference number creates no duplicate.&lt;/li&gt;
&lt;li&gt;A posted entry is never edited. A correction arrives as a new reversing entry, so the history stays intact.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Figures themselves are produced by deterministic, tested calculation from the ledger. The AI quotes figures; it does not invent them. A number in AI text that cannot be traced to a source is rejected in review.&lt;/p&gt;

&lt;h2&gt;
  
  
  A simple example
&lt;/h2&gt;

&lt;p&gt;On Tuesday morning the reconciliation agent finds a bank receipt that matches no open invoice. It drafts a proposal: allocate the receipt to a customer account, with the bank line and the likely invoice attached as evidence. The accountant reviews it, records the entry, and the finance manager approves it. If the allocation later proves wrong, a reversing entry fixes it, and the trail shows who proposed, who recorded, who approved and what changed.&lt;/p&gt;

&lt;h2&gt;
  
  
  A short checklist before you let AI near your ledger
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Every figure comes from tested calculation on the ledger, not from the model.&lt;/li&gt;
&lt;li&gt;Every AI draft is labelled as a proposal until a person approves it.&lt;/li&gt;
&lt;li&gt;Every proposal links to its entries, reconciliation items or documents.&lt;/li&gt;
&lt;li&gt;Each agent has a written list of what it may observe, draft and propose, and what it must never do.&lt;/li&gt;
&lt;li&gt;Recording and approval of sensitive changes are done by two different people.&lt;/li&gt;
&lt;li&gt;The record of proposals, edits and approvals is kept and exportable with the rest of your data.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The answer, in one line
&lt;/h2&gt;

&lt;p&gt;AI should prepare journal entries and find what is wrong; people should post and approve them. That keeps the speed of automation and the accountability of a controlled close.&lt;/p&gt;

&lt;p&gt;See how this works in Arfinex accounting, with AI agents and human approval: &lt;a href="https://arfinex.com/en/services/erp-accounting?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=w1_ai_journal&amp;amp;utm_content=d3" rel="noopener noreferrer"&gt;Arfinex ERP accounting with AI agents&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Arfinex builds software only. Local accounting and tax treatment is confirmed by your own accountant or adviser.&lt;/p&gt;

</description>
      <category>accounting</category>
      <category>ai</category>
      <category>fintech</category>
      <category>erp</category>
    </item>
    <item>
      <title>Building finance software where every number has a source</title>
      <dc:creator>Arfinex</dc:creator>
      <pubDate>Thu, 22 Oct 2026 07:44:03 +0000</pubDate>
      <link>https://dev.to/arfinex/building-finance-software-where-every-number-has-a-source-3l61</link>
      <guid>https://dev.to/arfinex/building-finance-software-where-every-number-has-a-source-3l61</guid>
      <description>&lt;p&gt;Most financial losses inside a company are not dramatic. They are small and repetitive: a duplicate supplier payment, a seat licence nobody uses, a payment fee a little above contract. Spotting them requires being able to trace every number back to where it came from.&lt;/p&gt;

&lt;p&gt;That idea sits at the core of Arfinex, the financial operating system for organizations, powered by AI agents. Arfinex LLC builds and provides the platform, which connects ledger, treasury, sales, payroll, contracts and operations in one current management view, in English, Persian, Arabic and Turkish.&lt;/p&gt;

&lt;h2&gt;
  
  
  Design principles
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No number without a source.&lt;/strong&gt; Every money movement links to the invoice, contract, bank line or report behind it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A balanced double-entry ledger as the reference system.&lt;/strong&gt; Balances are built from balanced entries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Corrections are reversals, not edits.&lt;/strong&gt; Approved reversing entries keep the audit trail intact.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI analyzes, people decide.&lt;/strong&gt; Specialist AI agents surface discrepancies and the decisions that need attention, draft entries and suggest matches. Postings, calculations and money movement follow deterministic, approved rules, and the manager keeps the final say.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Scope
&lt;/h2&gt;

&lt;p&gt;Arfinex is a software builder only. Payments, custody and identity checks are handled by licensed providers.&lt;/p&gt;

&lt;p&gt;Read the full article on the Arfinex website: &lt;a href="https://arfinex.com/en/insights/arfinex-smart-accounting" rel="noopener noreferrer"&gt;https://arfinex.com/en/insights/arfinex-smart-accounting&lt;/a&gt;&lt;/p&gt;

</description>
      <category>fintech</category>
      <category>ai</category>
      <category>accounting</category>
      <category>saas</category>
    </item>
  </channel>
</rss>
