<?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: Sebastian Dracopol</title>
    <description>The latest articles on DEV Community by Sebastian Dracopol (@dracopol).</description>
    <link>https://dev.to/dracopol</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%2F4158504%2F5925b133-30c8-456c-af02-730f033220d1.jpg</url>
      <title>DEV Community: Sebastian Dracopol</title>
      <link>https://dev.to/dracopol</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dracopol"/>
    <language>en</language>
    <item>
      <title>Safety Alignment Inverts the Tension–Response Curve in LLM Agents for Civil Violence Simulation</title>
      <dc:creator>Sebastian Dracopol</dc:creator>
      <pubDate>Sat, 10 Oct 2026 08:47:12 +0000</pubDate>
      <link>https://dev.to/dracopol/safety-alignment-inverts-the-tension-response-curve-in-llm-agents-for-civil-violence-simulation-32pf</link>
      <guid>https://dev.to/dracopol/safety-alignment-inverts-the-tension-response-curve-in-llm-agents-for-civil-violence-simulation-32pf</guid>
      <description>&lt;h2&gt;
  
  
  Abstract
&lt;/h2&gt;

&lt;p&gt;LLM-driven agent-based models (ABMs) replace a closed-form decision rule with an LLM agent. The idea is that the agent reproduces the qualitative behaviour of the original rule while adding context-sensitive reasoning. We test that assumption on Epstein's (2002) civil violence model. Across 600+ calibration conditions on a locally served Qwen 27B model (4-bit, MLX), the probability of choosing activation falls as scenario tension rises, from 41.5% at tension 0.10 to 12.6% at 0.90 under an &lt;em&gt;act/wait&lt;/em&gt; label pair. Epstein's rule predicts the opposite. Changing only the labels to &lt;em&gt;protest/comply&lt;/em&gt; restores a monotonically increasing response, from 0% to 95% over the same range. We break the observed distortion into lexical label priors, position bias and a tension-dependent anti-action component, and we hypothesise that the last one comes from safety alignment. We argue that LLM-ABM pipelines need a calibration stage, with a reported "bias budget", before agent behaviour is compared with mathematical baselines.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Background
&lt;/h2&gt;

&lt;p&gt;In Epstein's model each citizen agent computes a grievance term and a net-risk term:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Grievance: G = H · (1 − L), where H is perceived hardship and L is perceived government legitimacy.&lt;/li&gt;
&lt;li&gt;Net risk: N = R · P, where R is risk aversion and P is the estimated arrest probability. P = 1 − exp(−k · (C/A)_v), with (C/A)_v the cop-to-active ratio within the agent's vision radius.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The agent turns active when G − N &amp;gt; T.&lt;/p&gt;

&lt;p&gt;The rule is deterministic given state, and it produces a sharp increase in activation as legitimacy falls and hardship rises. That property makes it a usable reference: an LLM substitute that is valid at the decision level should be at least monotonically non-decreasing in G − N.&lt;/p&gt;

&lt;p&gt;In this work, the LLM agent gets a natural-language rendering of the same state variables and must return a binary choice.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Experimental setup
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Primary model&lt;/td&gt;
&lt;td&gt;Qwen 27B, 4-bit quantised, MLX, local inference&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Secondary model&lt;/td&gt;
&lt;td&gt;Mistral 7B Instruct v0.3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Temperature&lt;/td&gt;
&lt;td&gt;0.7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Repetitions per condition&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Conditions&lt;/td&gt;
&lt;td&gt;600+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Label order&lt;/td&gt;
&lt;td&gt;Counterbalanced&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tension levels&lt;/td&gt;
&lt;td&gt;0.10, 0.50, 0.70, 0.90&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Country prior (Romania)&lt;/td&gt;
&lt;td&gt;L = 0.21 (Eurobarometer), H = 0.55 (OECD), police density 0.003, R = 0.70&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Tension maps to model inputs as follows: &lt;code&gt;[describe: which of H, L, police presence vary with the tension scalar, and how]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Conditions vary along: &lt;code&gt;[list factors: label pair, prompt template, option order, persona attributes, ...]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The response is parsed by &lt;code&gt;[exact-match on label / constrained decoding / regex]&lt;/code&gt;, and invalid outputs are handled by &lt;code&gt;[dropped / re-sampled / counted as ...]&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Results
&lt;/h2&gt;

&lt;h3&gt;
  
  
  3.1 Act/wait: inverted response
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tension&lt;/th&gt;
&lt;th&gt;P(act)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0.10&lt;/td&gt;
&lt;td&gt;41.5%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0.50&lt;/td&gt;
&lt;td&gt;38.1%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0.70&lt;/td&gt;
&lt;td&gt;29.3%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0.90&lt;/td&gt;
&lt;td&gt;12.6%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The response is monotonically decreasing in tension. At 0.90, where the reference model predicts near-universal activation, the LLM agent activates in about 1 in 8 samples.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.2 Protest/comply: restored monotonicity
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tension&lt;/th&gt;
&lt;th&gt;P(protest)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0.10&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0.50&lt;/td&gt;
&lt;td&gt;20%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0.70&lt;/td&gt;
&lt;td&gt;35%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0.90&lt;/td&gt;
&lt;td&gt;95%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The curve has the expected shape, with a steep rise between 0.70 and 0.90, which matches the threshold behaviour of the reference rule.&lt;/p&gt;

&lt;p&gt;At n = 20 per cell, the 95% Wilson interval around 20% is about [8%, 42%]. The intermediate points should be read as directional until they are re-estimated with more samples or pooled across conditions.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.3 Label search
&lt;/h3&gt;

&lt;p&gt;Protest/comply was the only pair that produced a monotone response among the &lt;code&gt;[N]&lt;/code&gt; label pairs tested, including &lt;code&gt;[list]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Because the working pair was found by search, its performance is an in-sample result. It needs validation on held-out prompt templates before it can count as a calibrated configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Proposed mechanism
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Hypothesis.&lt;/strong&gt; Preference tuning (RLHF/DPO-style safety alignment) gives a negative prior on outputs that endorse unspecified "action" in high-conflict contexts. The penalty grows with how strongly the context signals conflict. That would explain why suppression increases with tension instead of staying constant.&lt;/p&gt;

&lt;p&gt;On this account, &lt;em&gt;protest&lt;/em&gt; escapes the penalty because the training data encodes it as a protected civic act, while &lt;em&gt;act&lt;/em&gt;, &lt;em&gt;rebel&lt;/em&gt; or &lt;em&gt;take action&lt;/em&gt; sit near content the alignment stage learned to refuse or discourage. &lt;em&gt;Wait&lt;/em&gt; draws a strong positive prior as a de-escalatory, "safe" completion.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Status.&lt;/strong&gt; The data here are consistent with this hypothesis but do not isolate it. A direct test is to compare base and aligned checkpoints of the same model family under identical prompts. The tension-dependent component should be present in the aligned checkpoint and absent, or much smaller, in the base one.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Cross-model observations
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Mistral 7B Instruct v0.3.&lt;/strong&gt; Its documentation does not describe a dedicated safety-tuning stage. It does not show the anti-action pattern. Instead it shows near-total primacy bias: it chooses whichever option is presented first in about 100% of samples, regardless of label or tension. The output carries no information about scenario state.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Base models.&lt;/strong&gt; These show smaller safety-type priors but larger social biases (in-group favouritism) and unreliable instruction following, so they cannot serve as drop-in agents.&lt;/p&gt;

&lt;p&gt;None of the three model classes gives an unbiased decision function without calibration.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Bias budget
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Magnitude&lt;/th&gt;
&lt;th&gt;Scope&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Primacy (first-option) bias&lt;/td&gt;
&lt;td&gt;~100%&lt;/td&gt;
&lt;td&gt;Mistral 7B&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Position bias&lt;/td&gt;
&lt;td&gt;5–16 pp&lt;/td&gt;
&lt;td&gt;&lt;code&gt;[model]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lexical prior on "wait"&lt;/td&gt;
&lt;td&gt;−45 pp on action&lt;/td&gt;
&lt;td&gt;Qwen 27B, act/wait&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tension-dependent anti-action&lt;/td&gt;
&lt;td&gt;−15 to −30 pp at high tension&lt;/td&gt;
&lt;td&gt;Qwen 27B&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Each of these effects is comparable to, or larger than, the behavioural differences the simulation is meant to resolve. Taken together they are enough to turn a predicted mass mobilisation into near-total quiescence.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Relation to existing frameworks
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;SocioVerse-ABM&lt;/strong&gt; (Fudan University / Shanghai Innovation Institute, v0.2.0, 2026) includes Epstein's model among twelve benchmark scenarios and evaluates GPT-4o, DeepSeek-V3 and Qwen3-235B against mathematical baselines. &lt;strong&gt;AgentTorch&lt;/strong&gt; (MIT Media Lab) supplies the computational patterns that make large-population LLM-ABMs feasible.&lt;/p&gt;

&lt;p&gt;Both frameworks compare agent output to a baseline. Neither, as far as we know, includes a pre-simulation step that separates decision-function distortion from emergent dynamics. Without that step, a deviation from baseline cannot be attributed to the model's reasoning rather than to its label and position priors.&lt;/p&gt;

&lt;p&gt;Li et al. (2025, ACM FAccT) report a related pattern: alignment reduces explicit bias while implicit bias persists or grows.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Recommendations
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Calibrate before simulating.&lt;/strong&gt; Sweep the decision inputs and check monotonicity and threshold location against the reference rule. If the check fails, do not run the population simulation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Report labels as a design parameter.&lt;/strong&gt; Report the label pair as a methodological choice, together with the alternatives that were tested.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Counterbalance option order&lt;/strong&gt; across agents and repetitions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Publish a bias budget.&lt;/strong&gt; Report the magnitude of each identified bias component alongside the substantive results.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prefer likelihood-based decisions over sampled text.&lt;/strong&gt; Score each label by its log-probability under the model, and calibrate by subtracting a content-free baseline (e.g., the same prompt with the state description replaced by a neutral placeholder). This removes label and position priors directly. With local inference the logits are available, so this is the next experiment to run, not a limitation.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  9. Limitations
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The study covers one primary model, one quantisation level and one country prior.&lt;/li&gt;
&lt;li&gt;The mechanism is proposed, not isolated (see §4).&lt;/li&gt;
&lt;li&gt;The working label pair was selected by search and has not been validated out of sample.&lt;/li&gt;
&lt;li&gt;Per-cell n = 20 gives wide intervals at intermediate tension levels.&lt;/li&gt;
&lt;li&gt;The decision is binary; Epstein's model also includes jailing dynamics, cop agents and spatial vision, none of which were exercised in calibration.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Data availability
&lt;/h2&gt;

&lt;p&gt;Full calibration data are available on request.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;Epstein, J.M. (2002). Modeling civil violence: An agent-based computational approach. &lt;em&gt;PNAS&lt;/em&gt;, 99(suppl. 3), 7243–7250.&lt;br&gt;
SocioVerse-ABM v0.2.0, Fudan University (2026).&lt;br&gt;
Li et al. (2025). Actions Speak Louder than Words. &lt;em&gt;ACM FAccT&lt;/em&gt;.&lt;br&gt;
AgentTorch, MIT Media Lab.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>simulation</category>
      <category>llm</category>
    </item>
    <item>
      <title>Trust nothing your AI assistant tells you it did published: false</title>
      <dc:creator>Sebastian Dracopol</dc:creator>
      <pubDate>Sat, 03 Oct 2026 10:58:01 +0000</pubDate>
      <link>https://dev.to/dracopol/trust-nothing-your-ai-assistant-tells-you-it-did-published-false-3hkp</link>
      <guid>https://dev.to/dracopol/trust-nothing-your-ai-assistant-tells-you-it-did-published-false-3hkp</guid>
      <description>&lt;p&gt;I use an AI every day for real work: reading mail, linking documents to files, drafting letters, tracking deadlines, researching on the web. It saves me hours a week. It also lies to me several times a week.&lt;/p&gt;

&lt;p&gt;It doesn't lie on purpose. It does something worse: it produces answers that look finished. They're well formatted, confident and plausible, and some fraction of them are wrong in ways you only notice if you go and check.&lt;/p&gt;

&lt;p&gt;After a year of this, my working assumption is simple. Every output is wrong until something outside the model says otherwise. This post explains why, and what "checking" actually means in practice.&lt;/p&gt;

&lt;h2&gt;
  
  
  The failure modes nobody puts in the demo
&lt;/h2&gt;

&lt;p&gt;Hallucination is the famous one, but in day-to-day work it isn't the most common problem. These are the failures I actually see.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reporting actions that didn't happen
&lt;/h3&gt;

&lt;p&gt;The assistant calls a tool to add a comment, send a draft or update a record. The call times out, returns an error, or succeeds on the wrong object. The assistant then writes "Done, comment added" because that's what the plan said would happen next.&lt;/p&gt;

&lt;p&gt;The narration comes from the plan, not from the result. If you read the narration, you'll believe it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Treating "nothing found" as a fact
&lt;/h3&gt;

&lt;p&gt;A search returns zero results, and the assistant concludes the thing doesn't exist. The real cause can be any of these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the page was a single-page app that hadn't loaded yet;&lt;/li&gt;
&lt;li&gt;the site served a captcha or a rate-limit page;&lt;/li&gt;
&lt;li&gt;the session had expired and the page silently showed a login screen;&lt;/li&gt;
&lt;li&gt;the query had a typo or used the wrong field.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An empty result is information about the search, not about the world. Last week my assistant got an HTTP 429 from a search engine on the first try. If I hadn't been watching, the next step would have been "no relevant results".&lt;/p&gt;

&lt;h3&gt;
  
  
  Answering from memory when the source changed
&lt;/h3&gt;

&lt;p&gt;Ask about a rule, a setting or an API, and the model answers from training data. Training data has a date. Interfaces change, laws get amended, menus move.&lt;/p&gt;

&lt;p&gt;A small example: I asked how to change a page's username on a large social network. The assistant searched, found three blog posts and confidently gave me a menu path. The path no longer existed in the current interface. The blog posts were consistent with each other and all out of date. The answer only became correct when the assistant opened the actual settings screen and read what was there.&lt;/p&gt;

&lt;h3&gt;
  
  
  Recommending things it never looked at
&lt;/h3&gt;

&lt;p&gt;This one is subtle and expensive. I asked for a plan to improve how a set of my public profiles ranked in search. The assistant produced a reasonable list of which profiles to strengthen and how. It had never opened them.&lt;/p&gt;

&lt;p&gt;When it finally did, several of those profiles contained exactly the content I didn't want to amplify. The plan was internally logical and completely wrong for my situation. In another case it told me to file a request that had already been filed weeks earlier. The record was one search away in my own knowledge base, and it didn't search.&lt;/p&gt;

&lt;h3&gt;
  
  
  Grading its own homework
&lt;/h3&gt;

&lt;p&gt;Ask a model "are you sure?" and it re-reads its own answer, finds it coherent, and says yes. Coherence is not correctness. Re-reading your own text checks the prose, not the facts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Losing detail over long sessions
&lt;/h3&gt;

&lt;p&gt;In long working sessions, the assistant's view of earlier steps gets summarized to fit its context window. The summary says "updated the deadline". It doesn't say which deadline, to what date, or whether the update succeeded. Later steps build on the summary as if it were the record.&lt;/p&gt;

&lt;h2&gt;
  
  
  What "verification" has to mean
&lt;/h2&gt;

&lt;p&gt;Most advice on this stops at "double-check AI output". That's useless unless you define what a check is. These are the rules I follow now.&lt;/p&gt;

&lt;h3&gt;
  
  
  A check is a tool call, not a thought
&lt;/h3&gt;

&lt;p&gt;Verification means touching something outside the model: reading the record back from the API, opening the page, running the query, fetching the current official text. "I reviewed my answer and it looks correct" isn't verification. It's the same model with the same blind spots, reading the same text again.&lt;/p&gt;

&lt;p&gt;If a claim can't be tied to a tool output, it gets marked as unverified. It doesn't get marked as true.&lt;/p&gt;

&lt;h3&gt;
  
  
  Actions are confirmed by the system that performed them
&lt;/h3&gt;

&lt;p&gt;"Email sent" counts when there's a message ID returned by the mail API, or when the message shows up in the Sent folder when you read it back. "Record updated" counts when the record, read back, shows the new value. The assistant's own summary of what it did doesn't count.&lt;/p&gt;

&lt;h3&gt;
  
  
  Negative results need a positive control
&lt;/h3&gt;

&lt;p&gt;When a search finds nothing, run the same search for something you know exists. If that also comes back empty, your method is broken, not the world. This one habit has saved me from a long list of false conclusions about missing data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Read the source that's in force today
&lt;/h3&gt;

&lt;p&gt;For anything that cites a rule, a setting or an interface, the check is against the current version of the source. Not a blog post about it, and not the model's memory of it. Store verified texts once so you don't fetch the same thing a hundred times, but record when you verified them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Look before recommending
&lt;/h3&gt;

&lt;p&gt;Before the assistant recommends doing something to an object (a profile, a document, a record), it opens that object and reads what's there now. A recommendation built on assumptions about content nobody looked at is a guess.&lt;/p&gt;

&lt;h3&gt;
  
  
  Search your own records first
&lt;/h3&gt;

&lt;p&gt;If you have a knowledge base, the assistant searches it before saying anything about your own past work. "You should file X" when X was filed last month costs credibility fast, and it's entirely avoidable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Separate "I couldn't check" from "I checked and it's fine"
&lt;/h3&gt;

&lt;p&gt;These two states look the same in a friendly summary, and they mean completely different things. A tool that failed to load is not evidence that the action happened, and it's not evidence that it didn't. Report it as what it is.&lt;/p&gt;

&lt;h3&gt;
  
  
  External effects need a human
&lt;/h3&gt;

&lt;p&gt;Anything that leaves your control (sending, publishing, filing, paying, deleting) needs explicit approval from a person. The assistant can do 95% of the work and stop one click before the irreversible part.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why bother, if it doubles the work
&lt;/h2&gt;

&lt;p&gt;It does roughly double the effort per workflow at first. The alternative is worse: an assistant that's right 90% of the time and wrong in ways that look identical to being right. You end up checking everything manually anyway, or you stop checking and find out the hard way.&lt;/p&gt;

&lt;p&gt;With verification built into the workflow, I can read a short report that says what was done, what was confirmed and how, and what couldn't be checked. Then I decide. That's the point where the time savings become real, because I spend my attention only on the parts that need it.&lt;/p&gt;

&lt;h2&gt;
  
  
  A short checklist
&lt;/h2&gt;

&lt;p&gt;If you take one thing from this post, use these questions on any AI output that matters:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What did it claim to do, and where is the system's confirmation?&lt;/li&gt;
&lt;li&gt;Which statements came from a tool output, and which from the model?&lt;/li&gt;
&lt;li&gt;Did any "nothing found" result get a positive control?&lt;/li&gt;
&lt;li&gt;Was the cited rule or interface checked against today's source?&lt;/li&gt;
&lt;li&gt;Did it look at the thing it's recommending changes to?&lt;/li&gt;
&lt;li&gt;What couldn't be verified, and is that clearly labeled?&lt;/li&gt;
&lt;li&gt;Does anything here leave my control without my approval?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;None of this is specific to one model or vendor. Every assistant I've used fails in these ways. The ones that are useful in real work are the ones wrapped in checks that don't take the model's word for anything.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I help small businesses and independent professionals build AI workflows they can trust. More at &lt;a href="https://dracopol.com/en" rel="noopener noreferrer"&gt;dracopol.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How I built my own AI tools for a small NGO instead of buying software</title>
      <dc:creator>Sebastian Dracopol</dc:creator>
      <pubDate>Sat, 03 Oct 2026 10:40:23 +0000</pubDate>
      <link>https://dev.to/dracopol/how-i-built-my-own-ai-tools-for-a-small-ngo-instead-of-buying-software-4eng</link>
      <guid>https://dev.to/dracopol/how-i-built-my-own-ai-tools-for-a-small-ngo-instead-of-buying-software-4eng</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnh5kuo8l7eajai7gyzuu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnh5kuo8l7eajai7gyzuu.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;Small nonprofits have the same paperwork as companies and none of the budget. When I started running one, the problems were familiar: hundreds of emails a month, documents arriving as PDFs, Word files and phone scans, deadlines spread across inboxes, and a small team trying to remember which reply belonged to which file.&lt;/p&gt;

&lt;p&gt;The software on the market was either expensive, generic, or built for sales teams. I've spent about twenty years in project and delivery management, so I did what I'd do on any project: broke the work into pieces and built the pieces myself. This time an AI assistant does most of the work, and I supervise.&lt;/p&gt;

&lt;p&gt;This post covers the architecture, the parts that failed, and the rules I added after they failed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start from the work, not from the model
&lt;/h2&gt;

&lt;p&gt;"We have an AI subscription, what can we do with it?" is the wrong first question. I started by writing down every repetitive task in a normal week and roughly how long each one took. Four came out on top:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Reading incoming mail and working out which file it belongs to.&lt;/li&gt;
&lt;li&gt;Turning documents into something searchable.&lt;/li&gt;
&lt;li&gt;Tracking deadlines and replies so nothing gets lost.&lt;/li&gt;
&lt;li&gt;Finding "that document from three months ago".&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;None of these needs intelligence in the impressive sense. They need consistency, memory and patience, which an assistant can provide if you give it structure and tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  The architecture
&lt;/h2&gt;

&lt;p&gt;The setup is an AI assistant (I use Claude) connected to a set of small tools through the &lt;a href="https://modelcontextprotocol.io/" rel="noopener noreferrer"&gt;Model Context Protocol&lt;/a&gt;. MCP is an open standard: each tool runs as a small server that exposes a few functions, and the assistant decides when to call them. A tool does one job. The assistant combines them.&lt;/p&gt;

&lt;p&gt;These are the servers I run.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mail and ticket connector
&lt;/h3&gt;

&lt;p&gt;This one reads the shared inbox, searches threads, downloads attachments and works with the project tracker (Jira). Each incoming message gets linked to the right ticket, with its attachments and a comment that summarizes what changed.&lt;/p&gt;

&lt;p&gt;It can also create drafts and send email, and that's exactly why sending is locked behind human approval. The assistant drafts. A person reads and approves. More on this below, because it was the most important design decision.&lt;/p&gt;

&lt;p&gt;The same server holds a small deadline register: add, update, supersede, remove and check. Every outgoing request gets a due date calculated from the rules that apply to it. When a date passes, the file comes back for a decision.&lt;/p&gt;

&lt;h3&gt;
  
  
  Document converter
&lt;/h3&gt;

&lt;p&gt;Everything that arrives (PDF, DOCX, XLSX, PPTX, HTML, ZIP) goes through a converter to Markdown before the model touches it. Plain text is cheaper to process, easier to search and easier to quote exactly.&lt;/p&gt;

&lt;p&gt;The exception is images. Modern models read a photo of a document better than OCR does, so images go straight to the model.&lt;/p&gt;

&lt;h3&gt;
  
  
  Private knowledge base
&lt;/h3&gt;

&lt;p&gt;All files, tickets, documents and replies are indexed in a vector database running on my own machine, with metadata such as source, ticket key and date. The assistant has &lt;code&gt;find&lt;/code&gt;, &lt;code&gt;store&lt;/code&gt;, &lt;code&gt;update&lt;/code&gt; and &lt;code&gt;reindex&lt;/code&gt; operations, plus search by entity.&lt;/p&gt;

&lt;p&gt;The rule is simple: for any question about our own work, the assistant searches the knowledge base first, and only after that the tracker or the web. Answers have to cite the chunk they came from. This one rule removed most hallucinated answers about our own history, because the model stops guessing when the real document is one call away.&lt;/p&gt;

&lt;h3&gt;
  
  
  Browser automation
&lt;/h3&gt;

&lt;p&gt;The assistant is told never to try to log in on the anonymous profile. Single-page apps get an explicit wait after each search, because an empty result two seconds after submit is a false negative, not a sign the data doesn't exist. Before long runs, a health check navigates to the authenticated sources and confirms the session is still alive. Having cookies doesn't prove you're logged in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Skills: writing the process down
&lt;/h2&gt;

&lt;p&gt;The tools were maybe 40% of the value. The rest came from writing down how we work as reusable instructions the assistant can load, which Claude calls "skills". Each one is a Markdown file with a trigger and a procedure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;one processes the morning's mail end to end: link, compare the reply with the original request point by point, update the deadline, recommend the next step;&lt;/li&gt;
&lt;li&gt;one audits an outgoing letter before it's sent;&lt;/li&gt;
&lt;li&gt;one runs a decision through five opposing perspectives (contrarian, first principles, expansionist, outsider, executor) plus a peer review before we commit;&lt;/li&gt;
&lt;li&gt;one looks for what's wrong with the previous answer and fixes it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Writing them forced us to make our process explicit, and that was worth doing for its own sake. A good share of the "AI problems" I fixed turned out to be "we never agreed how to do this" problems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verification
&lt;/h2&gt;

&lt;p&gt;AI assistants are confident even when they're wrong. Early on, mine:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;reported "comment added" when the tool call had failed silently;&lt;/li&gt;
&lt;li&gt;cited rules from memory instead of the version in force;&lt;/li&gt;
&lt;li&gt;treated an empty search result as proof that something didn't exist;&lt;/li&gt;
&lt;li&gt;filled gaps with plausible details.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So verification became part of the design instead of an afterthought.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Every claimed action needs the tool's response.&lt;/strong&gt; "Email sent" has to come with the message ID the API returned. If there's no tool output, the action didn't happen.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;References are checked against the current source.&lt;/strong&gt; Anything that cites a rule is checked against the official, up-to-date text, not the model's memory. The verified texts are stored once and reused, so the same source isn't fetched again for every document.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Negative results need a control.&lt;/strong&gt; If a search returns nothing, the same search must find a case we know exists. Otherwise "not found" is a property of the method, not a fact.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;There's a verification loop with a cap.&lt;/strong&gt; After important work, a verification pass looks for concrete problems (unconfirmed actions, unsourced claims, contradictions, unstated assumptions), fixes them in place and runs again until nothing changes. The cap is 5 passes for tool-backed actions and 2 for pure text judgment, so it can't loop forever.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Humans approve external effects.&lt;/strong&gt; Sending, publishing and filing need explicit approval. The assistant can prepare everything up to the last click.&lt;/p&gt;

&lt;p&gt;Building this roughly doubled the effort for each workflow. It's also the only reason I trust the output.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changed
&lt;/h2&gt;

&lt;p&gt;The measurable gain is time. Sorting a morning's mail, matching it to files and updating deadlines used to take a morning. Now it's a few minutes of review.&lt;/p&gt;

&lt;p&gt;The less obvious gain is memory. Nothing depends on one person remembering where a document is or when something is due.&lt;/p&gt;

&lt;p&gt;The costs are real too. The assistant still needs supervision. Tools break when a website or an API changes. Some days doing the task by hand is faster than explaining it.&lt;/p&gt;

&lt;h2&gt;
  
  
  If you want to build something similar
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;List your repetitive tasks and time them. Automate the top two, not everything.&lt;/li&gt;
&lt;li&gt;Keep your data where you control it. A local vector database is cheap and solves most privacy questions, which matters if you handle personal data under GDPR.&lt;/li&gt;
&lt;li&gt;Build small tools that do one thing, and let the assistant combine them.&lt;/li&gt;
&lt;li&gt;Write the process down as instructions. That's where most of the value is.&lt;/li&gt;
&lt;li&gt;Don't skip verification or human approval for anything that leaves the building.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I now help small businesses and independent professionals build the same kind of setup for their own work. You can find me at &lt;a href="https://dracopol.com/en" rel="noopener noreferrer"&gt;dracopol.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mcp</category>
      <category>automation</category>
      <category>ngo</category>
    </item>
  </channel>
</rss>
