Project 5: Deterministic Counter Agent

Quick Reference

Attribute Value
Difficulty 2
Time 1.5 weeks
Main Stack jido + optional jido_action
Alternatives GenServer-only counter, ETS counter
Why Now Clean baseline for understanding cmd/2 invariants

What You Will Build

A pure agent state machine that increments and snapshots counters through explicit actions, proving that state transitions are deterministic and testable using only function-level operations.

Real World Outcome

$ mix test test/counter_agent_test.exs
.....
Finished in 0.4 seconds (0.00s async, 0.4s sync)
All tests passed

The counter state should be reproducible from event history:

  • start_count=0
  • after three increment actions => 3
  • after reset action => 0

The Core Question You Are Answering

“What guarantees do we get when state transitions are modeled as pure cmd/2 operations instead of mutable process logic?”

Why This Project Matters

Jido’s design emphasizes pure transformation in cmd/2: action input + state in, transformed state + directives out. This gives deterministic behavior and easier reasoning for testing and audit.

Core Architecture

Input Action
    |
    v
+----------------------+
| Action module        |
| validate schema      |
| create update delta   |
+----------+-----------+
           |
           v
+----------------------+
| Agent.cmd(agent, act) |
| returns state_update  |
| + directive list      |
+----------+-----------+
           |
   +-------+--------+
   |               |
   v               v
Updated State   External Effects
 (agent state)    (Emit, none in this project)

Deep Dive Plan

1. State Schema

Define a tiny schema:

  • count integer
  • version integer
  • optional metadata map

2. Actions

Implement and validate:

  • Increment
  • Decrement
  • Reset
  • SetStep

3. Command Contract

Enforce invariants:

  • command result always has complete agent
  • directives must never mutate state
  • impossible transitions return explicit errors ({:error, reason})

4. Test First

Test:

  • deterministic replay of action history
  • property-style checks for commutative increments and boundaries
  • schema validation failures

5. Runtime Integration

Add agent server lifecycle:

  • start/persist local registry ID
  • synchronous vs asynchronous signal entry points

Concepts You Must Understand First

  1. cmd/2 contract
    • returned state+directives pattern and purity.
  2. State schema validation
    • schema errors are control signals, not runtime noise.
  3. Directive isolation
    • directives describe effects; they do not touch state directly.

Questions to Guide Your Design

  1. Testability
    • What test gives proof of deterministic replay?
  2. Validation
    • Which invalid actions should be hard-fail immediately?
  3. Concurrency
    • How do multiple signals to same agent preserve consistency?

Thinking Exercise

Given action sequence: Increment(2), Increment(3), Decrement(1), Reset, Increment(5), what is final state?

Then add one faulty action Increment("bad"). Predict full command result behavior.

Interview Questions They Will Ask

  1. “What is the significance of returning a complete state in cmd/2?”
  2. “Why are directives separated from state transitions?”
  3. “How do you model failed transitions in tests?”
  4. “What makes deterministic replay practical in production?”
  5. “How does jido improve on raw GenServer for this case?”

Hints in Layers

Hint 1: Start with one state schema No branching until schema is locked.

Hint 2: Keep actions tiny One action should mean one transition.

Hint 3: Enforce explicit errors Never raise on bad action data inside action handlers.

Hint 4: Build a replay script Serialize action list -> apply from zero -> assert final state.

Common Pitfalls and Debugging

  • Problem: Tests pass but runtime state drifts.
    • Why: runtime adapter mutated state outside cmd/2.
    • Fix: route all updates through action handlers only.
    • Quick test: inspect code paths and ensure no direct state assignment.
  • Problem: Directive logic leaking into state.
    • Why: effect branch writes state map.
    • Fix: isolate directives as output, never state input.
    • Quick test: assert state hash unchanged when directive-only action runs.
  • Problem: Invalid schema silently coerced.
    • Why: overly permissive schema defaults.
    • Fix: strict validation defaults and explicit error returns.
    • Quick test: pass invalid action values intentionally.

Books That Will Help

Topic Book Chapter
Pure function design Elixir in Action State and Data Structures
OTP and processes Programming Elixir GenServers and message design

Definition of Done

  • State transitions are deterministic for the same action history
  • Invalid actions return structured errors
  • directives remain separate from state mutation
  • test suite validates replay semantics
  • agent server lifecycle works with one-line start/stop calls

References

  • https://hexdocs.pm/jido/2.0.0-rc.4/readme.html
  • https://hexdocs.pm/jido/2.0.0-rc.4/readme.html#The%20cmd/2%20Contract