🧠 Active Inference
Experimental code for suggesting what to do next from a model of a person’s day. Active Inference is a Python project that is designed to keep beliefs about a person’s energy, mood, and context, update them from records of events, people, places, and content, and suggest an action by minimizing expected free energy. At v0.1.0 the main engine doesn’t run end to end: its API fails to import, and its demo and train commands fail when they create the agent. The forage sampler is the one service that starts.
Status: experimental, source only. The v0.1.0 pre-release on GitHub attaches a source distribution and a wheel. The package isn’t on PyPI, there is no container image, it isn’t a Companion Hub app, and it has no user interface. The release notes say the install was not exercised, the test suite was not run, and the repository has no CI workflow. It isn’t connected to Companion Memory, the personal memory product. Read Limitations before you try it.
Overview
Active inference is a framework for choosing actions. An agent holds beliefs about hidden states, predicts what it will observe, and picks the action expected to reduce its uncertainty and move it toward what it prefers. This project uses the discrete form of that idea, built on the pymdp library.
The agent in ci_active_inference/agents/__init__.py models a person like this:
| Part | What it holds |
|---|---|
| Hidden states | Energy (low, medium, high), mood (negative, neutral, positive), and context (work, personal, social, health, learning) |
| Observations | Digital behavior, location context, social context, and content |
| Actions | Nine suggestions, such as “Take a break and rest to restore energy” and “Learn something new” |
| Learning | Dirichlet updates to the likelihood and transition matrices |
The repository holds two Python packages:
ci_active_inference— the model above, a data access layer, a FastAPI service, and modules for explanations, monitoring, multi-step planning, and A/B testing.ci_forage— a separate sampler that applies discrete active inference to a toy “memory lake”. Its example asks where a person named Sam is on Saturday. It doesn’t read Companion Memory, and it doesn’t use the agent, the database, orpymdp.
What is in the repository
- Forage service —
./run_forage_api.shstarts theci_forageapp on port8003, with routes such as/ask,/sample,/probe, and/resolve. It is the one service that runs as shipped. - Command line —
python main.pytakesinit-db,sample-data,demo,train, orstatus.demoandtrainfail; see Limitations. - API service —
./run_api.shis meant to start a FastAPI app on port8000. At v0.1.0 the app’s module fails to import, so nothing is served. The source defines routes to create and list people, places, things, content, and events, plus/inference/predict,/inference/recommend-actions,/inference/update-beliefs, and/optimization/user-schedule/{person_id}. - Tests — a
tests/folder that./run_tests.shruns with pytest. - Release files —
ci_active_inference-0.1.0-py3-none-any.whlandci_active_inference-0.1.0.tar.gz, attached to the pre-release.setup.pycollects Python packages withfind_packages()and declares no console script or entry point, andmain.pyisn’t inside a package.
Technical architecture
flowchart TB
accTitle: How the Active Inference code is organized
accDescr: The command line and the API are written to call an agent. The agent reads system state from a data access layer over PostgreSQL and returns beliefs and a suggested action. At v0.1.0 the API module fails to import. A separate forage service runs on a built-in toy example and doesn't use the agent or the database.
CLI["main.py<br/>command line"] --> Agent
API["FastAPI, port 8000<br/>fails to import at v0.1.0"] --> Agent
DB[("PostgreSQL<br/>DATABASE_URL")] --> DAO["Data access layer"]
DAO --> State["System state"]
State --> Agent["Agent<br/>states · observations · actions"]
Agent --> Out["Beliefs, confidence,<br/>suggested action"]
Forage["ci_forage<br/>FastAPI, port 8003"] --> Toy["Built-in toy example"]- Data access:
ci_active_inference/database/connects to PostgreSQL withpsycopg2, creates tables such as users, people, places, things, content, and events, and reads them through data access objects. The module’s docstring says it implements the Companion Memory server’s schema. - Agent:
PyMDPActiveInferenceAgentencodes the current system state as observations, infers hidden states, scores policies by expected free energy, and returns beliefs, a confidence value, and a suggested action.update_modeladjusts the matrices from new observations. - Service layer:
main.pyandci_active_inference/api/__init__.pyare written to call the agent, and both fail at v0.1.0; see Limitations. The API’s code sets cross-origin rules to allow every origin and has no authentication. - Forage:
ci_foragekeeps the current trials in memory and writes each trial as a JSON file, named by trial ID, to the folder set withFORAGE_DATA_DIR. When that variable isn’t set, the files go toci_forage/var/trialsinside the package.
Requirements
| Area | What the repository documents, and where the code differs |
|---|---|
| Operating system | Linux. The setup notes target Ubuntu 20.04 or later |
| Python | The README and setup.py say 3.8 or later. The forage service needs 3.10 or later |
| Resources | At least 2 GB of RAM and 1 GB of free disk space |
| Database | PostgreSQL, set with DATABASE_URL, for ci_active_inference. The forage service doesn’t use a database |
| Packages | requirements.txt, plus the pymdp library, which the code imports but requirements.txt and setup.py don’t list. The forage service needs only NumPy, FastAPI, pydantic, and Uvicorn |
Run the forage sampler
The forage service is the one part of the repository that runs as shipped. It needs Python 3.10 or later, and it doesn’t need PostgreSQL or pymdp.
Get the source
git clone https://github.com/companionintelligence/CI-Active-Inference.git
cd CI-Active-InferenceInstall the packages
python3 -m venv .venv
source .venv/bin/activate
pip install numpy fastapi pydantic uvicornStart the service
API_HOST=127.0.0.1 ./run_forage_api.sh # port 8003, reloads on file changesrun_forage_api.sh activates .venv or venv if one exists. It listens on all interfaces unless you set API_HOST, and it uses the port in FORAGE_PORT, which defaults to 8003. It runs Uvicorn with --reload, which keeps running after an error in the server process, so read the log if a request gets no answer.
Usage
According to the docstring in ci_forage/api.py, an empty POST /ask loads the built-in example, and one trial is current at a time. Then POST /sample reads the next item:
curl -X POST http://localhost:8003/ask
curl -X POST http://localhost:8003/sample
curl http://localhost:8003/traceOpen http://localhost:8003/docs for the interactive reference.
Set up the main package
The main package needs a PostgreSQL database and a release of the pymdp library that still has pymdp.maths.softmax, such as 0.0.7.1. These steps follow the repository’s README with the corrections from Limitations. They leave out demo, train, and the API, which fail as shipped. The three commands they run, init-db, sample-data, and status, don’t create the agent, but they weren’t run for this page because they need a PostgreSQL server.
export DATABASE_URL=postgresql://USER:PASSWORD@localhost:5432/ci_active_inference
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt "inferactively-pymdp==0.0.7.1"
python main.py init-db
python main.py sample-data
python main.py statusThe code reads environment variables and nothing in it loads the .env file, so exporting DATABASE_URL in your shell is what takes effect. The README’s ./setup.sh installs only requirements.txt and stops at its init-db step because pymdp is missing, so run these steps instead.
Limitations
The first four items were checked against v0.1.0 on 30 October 2026. Each says what was run.
- The API doesn’t start.
ci_active_inference/api/__init__.pyimportsget_dbfromci_active_inference.database, and that module defines noget_db, so importing the API raisesImportError: cannot import name 'get_db'. Without--reload,uvicorn ci_active_inference.api:appexits with that error../run_api.shadds--reloadby default, so it printsUvicorn running on ...and starts a reloader, but the server process dies with the same error and the reloader keeps waiting for file changes. No request is answered, not even the interactive documentation at/docs. Checked on Python 3.12 withrequirements.txtinstalled, by importing the module and by starting it withuvicorn, and by running./run_api.shwithAPI_HOST=127.0.0.1on Python 3.9. demoandtrainfail. Both create the tables and sample data, then callCIActiveInferenceAgent()with no arguments.demogoes on to callpredict_future_stateandrecommend_actions, andtraincallsupdate_beliefs. The class that name refers to,PyMDPActiveInferenceAgent, requires auser_idand defines none of those methods. The functions behind both commands raiseTypeError: PyMDPActiveInferenceAgent.__init__() missing 1 required positional argument: 'user_id'as soon as they create the agent.SimpleActiveInferenceAgentinagents/simple_agent.pydefines the methods the commands call. Checked by calling those functions on Python 3.12 withinferactively-pymdp0.0.7.1 installed, without a database.pymdpisn’t declared, and its current release doesn’t fit.ci_active_inference/agents/__init__.pyimportspymdp, butrequirements.txtandsetup.pydon’t list it. On a clean install,main.pystops withModuleNotFoundError: No module named 'pymdp', and so does./setup.sh. The package namedpymdpon PyPI is an unrelated project. The library is published asinferactively-pymdp, and the repository pins no version. The imports inagents/__init__.pywork withinferactively-pymdp0.0.7.1. With 1.0.4,from pymdp.maths import softmaxraisesImportError. Checked with./setup.shon Python 3.9, and withmain.pyand the imports on Python 3.12. The agent’s behavior was not checked.- The forage service needs Python 3.10 or later.
ci_forage/api.pyannotates its request models withstr | None. On Python 3.9, importing it raisesTypeError: Unable to evaluate type annotation 'str | None'.run_forage_api.shuses--reload, so it still printsUvicorn running on ..., the server process dies with that error, and requests get no answer. The README andsetup.pysay 3.8 or later, andinferactively-pymdp1.0.x also needs 3.10 or later. Checked by importing the module and by runningrun_forage_api.shon Python 3.9.6. - PostgreSQL, not SQLite. The README and
SETUP.mddescribe SQLite as the default database and mentionDATABASE_PATH. The database module thatmain.pyand the API use connects to PostgreSQL throughpsycopg2, and nothing inmain.pyor the API readsDATABASE_PATH. - No supported install. The wheel and source distribution were built from the v0.1.0 tag, but the release notes say the install was not exercised and the test suite was not run. There is no CI workflow.
- No authentication. Neither service has a sign-in. The main API’s code allows requests from any origin, and both run scripts listen on all interfaces unless you set
API_HOST. Run them only on a network you trust. - Not connected to Companion Memory or Hub. The code makes no calls to the Companion Memory API or any other service over HTTP. It reads the database you point it at. It isn’t a Hub app and has no Marketplace entry.
- No user interface. The README’s plan describes a web front end. None is in the repository.
- The roadmap is a plan. The README’s 16-week checklist has 30 items and none is checked off, so it doesn’t tell you which parts are built.
License
Companion Active Inference is free for noncommercial and research use under the PolyForm Noncommercial License 1.0.0 . Commercial use, including paid access to a hosted instance, isn’t permitted. See the repository’s License FAQ .
Links
- GitHub repository (companionintelligence/CI-Active-Inference) — source
- v0.1.0 pre-release — source distribution and wheel
- pymdp documentation — the active-inference library the agent uses
- Architecture of the public Companion systems
- Companion Memory