# dev defined twice, ports published on every interface, and a Skill that is four files on a mount

> Anima is a Python agent runtime for household hardware, currently limited to Mi Home and MIoT devices, driving real appliances through LangGraph planners and MQTT. The interesting parts are the configuration seams: two conflicting dev dependency sets, a compose file that publishes its API on all interfaces, and skills that live on a bind mount where editing a file changes runtime behaviour.

**Fullive-AI/Anima** — Make Every Hardware Intelligent — an open-source Agent OS for hardware intelligence

- Repository: https://github.com/Fullive-AI/Anima
- Stars: 1,037 · Forks: 42
- Language: Python
- License: Apache-2.0
- Published: 2026-09-17 · Updated: 2026-09-17 · Language: en
- Canonical page: https://hysenlabs.com/projects/fullive-ai-anima

## dev is defined twice with floors that do not overlap

pyproject.toml carries two separate dev lists. The optional extra named dev asks for pytest>=8.0.0, pytest-asyncio>=0.24.0, pytest-cov>=5.0.0, ruff>=0.8.0 and pre-commit>=4.0.0. The dependency group also named dev asks for pytest>=9.0.3, pytest-asyncio>=1.3.0 and pytest-timeout>=2.4.0. Same package names, floors a major version apart on the first two, and no overlap in the tails: coverage, linting and hooks live only in the extra, timeouts live only in the group. Which one you get depends on how you invoke the toolchain, and package.json makes the choice for you by running `uv sync --extra dev --python 3.13` in postinstall, which resolves the extra. Anyone who runs a group-based sync instead silently lands on a different pytest and a different asyncio plugin.

## Three services publish on every interface, and the API binds 0.0.0.0

The compose file maps `"${ANIMA_MQTT_PORT:-1883}:1883"`, `"${ANIMA_API_PORT:-8080}:8080"` and `"${ANIMA_DASHBOARD_PORT:-3000}:80"` with no loopback prefix on any of them, and the core service sets `ANIMA_API_HOST: 0.0.0.0`. So on a default `docker compose up`, a FastAPI service that controls real household appliances is reachable from the local network on port 8080. The same service receives `ANIMA_XIAOMI_CLOUD_USER` and `ANIMA_XIAOMI_CLOUD_PASS` from the environment, defaulting to empty strings, which are the account the QR login path uses to obtain device tokens. Neither the compose file nor the README states an authentication requirement for the REST API or for the broker. The port defaults can be changed, but nothing in the shipped configuration asks you to.

## The container always installs the Xiaomi stack the project calls optional

python-miio>=0.5.9 sits in an optional extra named miot, alongside the unconditional list of fastapi, uvicorn, aiomqtt, langgraph, openai, langchain-openai, pydantic, pydantic-settings, pyyaml, httpx, rich, socksio, amqtt and matplotlib. The Dockerfile makes that extra mandatory regardless, running `uv sync --frozen --no-dev --extra miot --no-install-project` after copying only pyproject.toml and uv.lock. That matters because Mi Home and MIoT are the only devices the project currently supports. So a container always carries the Xiaomi stack, while a local install that omits the extra removes the only device integration the runtime has. The image is python:3.13-slim even though requires-python allows 3.11 up to below 3.14, and the same 3.13 is pinned again in the postinstall hook.

## A Skill is a four file contract, and skills/ is a live bind mount

The Skill layout is specified file by file:

```text
SKILL.md              # skill metadata, supported devices, and operating rules
references/
  knowledge.md        # domain knowledge
  decide.md           # single-decision prompt
  learn.md            # long-term learning prompt
scripts/
  actions.py          # structured action execution entrypoint
```

Eight are built in, `light`, `humidifier`, `air_conditioner`, `air_purifier`, `speaker`, `coordinator`, `device_discovery` and `skill_creator`, and your own go under skills/custom/. Compose mounts `./skills:/app/skills`, so a Skill you edit on the host is the Skill the runtime loads, with no rebuild step. The same trick applies to state: the image creates data/memory/users/default and compose bind mounts ./data over /app/data. The documented rule for adding a device type is to extend Skills rather than hardcode policy into the Brain or an Adapter.

## Two broker implementations, one port, and a three step health chain

The dependency list names both aiomqtt and amqtt, there is an amqtt.yaml at the repository root, and the package.json script `dev:broker` starts `.venv/bin/amqtt -c amqtt.yaml`. Compose runs something else entirely, the eclipse-mosquitto:2 image with `./mosquitto/mosquitto.conf` mounted over its config. So local development and the container arrangement do not run the same broker. The startup order is expressed with health conditions rather than plain depends_on, core waits for mqtt to be healthy and dashboard waits for core, and each service proves itself differently: mosquitto publishes to the anima/healthcheck topic, core runs a Python one-liner that opens http://127.0.0.1:8080/health, and dashboard runs wget with --spider against http://127.0.0.1/health. The dashboard is the only service whose health check is a shell utility rather than an interpreter.

## The third core pillar is a heading that stops mid-word

The Core Highlights section has three numbered pillars. The first two are described in full: the Brain as the central decision layer, then Skill as the smallest unit of device intelligence. The third begins with the line `### 3. Memory: Evidence-Bas` and the document ends there, so the memory pillar is introduced by a truncated heading and has no body text at all. What can be said about memory comes from an earlier question block instead, which names a preferences.md file, normalized learned profiles per device type and extracted topic memories, and says the Brain pulls preferences incrementally out of interaction history. What that section does not establish, because it never arrives, is how those pieces are structured or when they are consulted.

## The Brain states its own boundary, then ships with gpt-4o and no key

The Brain section is explicit about intent, saying its purpose is not to let an LLM control devices freely and that decisions happen inside explicit skill boundaries, device capabilities and safety rules. The mechanics listed are LangGraph based planner and executor flows, a unified chat entrypoint at /api/chat, scheduled brain ticks for proactive environment checks, context construction before a skill runs, and state verification plus history writes after actions. Configuration is OpenAI compatible, so any such endpoint works, with providers named as OpenAI, DeepSeek, Doubao, Anthropic through a proxy and local Ollama compatible endpoints, which is why Anthropic needs the proxy rather than being addressed directly. Two environment values need attention out of the box: ANIMA_LLM_API_KEY defaults to an empty string, and ANIMA_LLM_MODEL defaults to gpt-4o.

## Four instruction documents, two languages, and no tagged release

The root carries AGENT.md and CLAUDE.md side by side, plus ARCHITECTURE_GUARDRAILS.md with a zh-CN twin, plus README.md with README.zh-CN.md, and CONTRIBUTING.md, SECURITY.md and CHANGELOG.md. Machine-enforced rules sit alongside the prose ones: .pre-commit-config.yaml, ruff.toml and .editorconfig, with .python-version and .nvmrc pinning the two toolchains and a pnpm-workspace.yaml alongside uv.lock. There are no GitHub releases, and both manifests sit at 0.1.0 while package.json is marked private, so there is no published version to pin and nothing to compare a checkout against. The dev scripts assume a POSIX layout as well, since the backend and broker entries point at `.venv/bin/python` and `.venv/bin/amqtt` by path rather than resolving them.

## Conclusion

It fits someone who already runs Mi Home hardware and wants a local controller they can read, extend through skills, and drive from a dashboard, a REST API or a CLI. It does not fit a deployment on an untrusted network in its current form, because the compose file publishes the API, the broker and the dashboard on every interface and the visible configuration says nothing about authenticating callers who can then move real appliances. Before exposing it, bind the three published ports to loopback or put a reverse proxy with authentication in front, decide which of the two dev dependency sets your environment should follow, and remember that the third core pillar is documented only as far as a heading that stops mid-word.

## FAQ

### Which smart home devices does Anima support?

Mi Home and MIoT devices are the only ones currently supported. Device discovery, QR login and device activation are handled by the device_discovery skill, and the python-miio integration is shipped as the miot extra.

### What files make up an Anima Skill?

SKILL.md for metadata and operating rules, references/knowledge.md, references/decide.md and references/learn.md for the knowledge and prompts, and scripts/actions.py as the structured action entrypoint. Custom skills go under skills/custom/.

### Which LLM providers can Anima talk to?

Any OpenAI compatible API, with OpenAI, DeepSeek, Doubao, Anthropic through a proxy and local Ollama compatible endpoints named in the project. Configuration is ANIMA_LLM_API_KEY plus an optional ANIMA_LLM_BASE_URL.

### Does the Anima docker compose setup expose its API to the network?

The published ports carry no loopback prefix and the core service sets ANIMA_API_HOST to 0.0.0.0, so the API, the broker and the dashboard bind on all interfaces by default. No authentication requirement is stated for the REST API in the compose file or the README.

### Why does Anima have two sets of dev dependencies?

pyproject.toml defines dev twice, once as an optional extra pinning pytest 8 and pytest-asyncio 0.24 with coverage, ruff and pre-commit, and once as a dependency group pinning pytest 9 and pytest-asyncio 1.3 with pytest-timeout. The postinstall hook syncs the extra.

## Sources

- [Fullive-AI/Anima on GitHub](https://github.com/Fullive-AI/Anima)
- [Issues](https://github.com/Fullive-AI/Anima/issues)
- [License: Apache-2.0](https://github.com/Fullive-AI/Anima/blob/main/LICENSE)
- [README](https://github.com/Fullive-AI/Anima/blob/main/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/fullive-ai-anima
