Your own self-evolving AI agent
A long-running agent that works in the chat apps you already use, calls tools, remembers context, and keeps improving through real-world use.
NexAgent is an AI agent built for real-world, long-running use.
It is not just a one-shot CLI demo, and it is not just a thin prompt wrapper around a model. NexAgent is built around a more specific goal: keep an agent online, place it inside the chat apps you already use, give it memory and tools, let it manage background work, and make it capable of improving over time.
Two ideas define the project today:
- Self-evolution: not only prompt engineering, but also memory, skills, tools, and source-level self-improvement.
- Elixir/OTP: supervision trees, GenServers, process isolation, and hot code loading for fault tolerance, concurrency, and long-lived operation.
If you only remember three things about NexAgent, they should be:
- What it is: a long-running AI agent that lives in chat apps
- What it can do: memory, tools, skills, scheduled jobs, and background tasks
- Why it can keep running: Elixir/OTP plus built-in self-evolution paths
flowchart TD
A["Chat Apps<br/>Telegram / Feishu / Discord / Slack / DingTalk"] --> B["Gateway"]
B --> C["InboundWorker"]
C --> D["Runner"]
D --> E["Sessions + Memory"]
D --> F["Tools + Skills"]
D --> G["Cron + Subagent"]
D --> H["Reflect + Upgrade Code"]
H --> I["CodeUpgrade + UpgradeManager"]
| Use case | What NexAgent is doing |
|---|---|
| Always-on assistant | Stays in your chat apps and keeps per-chat context over time |
| Personal knowledge agent | Combines long-term memory, history, and retrieval |
| Automation assistant | Uses cron for reminders, recurring jobs, and background work |
| A growing agent | Expands through skills, tools, and code-level self-improvement |
| Capability | What it means |
|---|---|
| Self-evolving by design | soul_update, memory_write, skill_create, tool_create, reflect, and upgrade_code keep the agent from staying static |
| Long-running sessions | Sessions are scoped by channel:chat_id and keep memory, history, and isolation |
| Works in your chat apps | Telegram, Feishu, Discord, Slack, and DingTalk are already supported |
| Tools, skills, and memory built in | File access, shell, web, messaging, memory search, scheduling, and skills come built in |
| Background work included | Cron jobs and subagents are part of the system, not an afterthought |
| Built on Elixir/OTP | Supervision trees, service processes, and hot reload support real-world uptime |
Many agent projects are good at finishing a single task. NexAgent is focused on a different set of questions: once an agent is actually deployed into chat environments and kept online, how should sessions, memory, jobs, failure handling, and self-improvement be organized?
NexAgent is not differentiated by “one more tool” or “one more model.” Its real difference is that evolution is treated as a core system capability.
That path is layered:
SOUL.md: adjust behavior, tone, and valuesMEMORY.md/HISTORY.md/ daily logs: accumulate long-term experience- Skills: turn new abilities into reusable building blocks
- Tools: expand what the agent can actually do
- Code: use
reflectandupgrade_codeto inspect and modify the agent itself
That is why “self-evolving” is not just a slogan here. It is a direction that runs from prompt and memory all the way down to source code.
If an agent only runs once in a while, the runtime matters less. If it needs to stay online, manage multiple chat surfaces, run background work, recover from failures, and eventually hot-upgrade itself, OTP stops being an implementation detail and becomes part of the product.
NexAgent already follows that path in code:
Applicationmanages infrastructure, workers, and channel lifecycles through a supervision treeGatewaymanages chat app connectionsInboundWorkerconsumes inbound messages and routes sessionsSessionManager,Tool.Registry,Cron, andSubagentrun as long-lived servicesCodeUpgradeandUpgradeManagerhandle hot updates, versioning, and rollback paths
That is why Elixir/OTP is not background trivia in this project. It is one of the main reasons the project exists in this form.
NexAgent is not trying to solve “how do we wrap one more model call.” It is trying to solve a more operational set of problems:
| Traditional agent prototype | What NexAgent is aiming for |
|---|---|
| One-off tasks in a CLI | Long-lived agents inside chat apps |
| Mostly depends on the current context window | Sessions, memory, history, and retrieval |
| New capabilities mainly come from prompt edits | Tools, skills, and code-level self-improvement |
| Failures tend to kill the whole turn | OTP supervision and long-lived services keep the system stable |
| Capabilities are mostly fixed after deployment | The agent keeps evolving while it runs |
Requirements:
- Elixir
~> 1.18 - Erlang/OTP
Install dependencies:
git clone https://github.com/gofenix/nex-agent.git
cd nex-agent
mix deps.getmix nex.agent onboardYou can also point the CLI at a specific instance:
mix nex.agent -c /path/to/config.json -w /path/to/workspace onboardOn first run, NexAgent creates the config and workspace for that instance:
~/.nex/agent/
├── config.json
├── tools/
└── workspace/
├── AGENTS.md
├── SOUL.md
├── USER.md
├── skills/
├── sessions/
└── memory/
├── MEMORY.md
├── HISTORY.md
└── YYYY-MM-DD/log.md
The most direct path is to set provider, model, and API key through the CLI:
mix nex.agent config set provider openai
mix nex.agent config set model gpt-4o
mix nex.agent config set api_key openai sk-xxxIf you want to use Ollama:
mix nex.agent config set provider ollama
mix nex.agent config set model llama3.1Default providers:
anthropicopenaiopenrouterollama
Provider access is unified through req_llm, so NexAgent no longer needs a
separate handwritten client module for each provider.
Config file location:
~/.nex/agent/config.json
If you pass --config and do not set defaults.workspace, the workspace defaults to
Path.dirname(config.json)/workspace for that instance.
The CLI is a host shell for the agent runtime. Capability-specific actions stay inside the agent loop through tools and skills; the CLI itself only manages sessions and runtime state.
Single message:
mix nex.agent -m "hello"Interactive mode:
mix nex.agentmix nex.agent gatewayCheck status:
mix nex.agent statusTarget a specific instance:
mix nex.agent -c /path/to/config.json status
mix nex.agent -c /path/to/config.json -w /path/to/workspace gatewayStop the gateway:
mix nex.agent gateway stopNexAgent is not meant to live only in a terminal.
The goal is to place the agent inside the chat apps you already use, so it becomes part of real communication and workflows.
Currently supported in code:
| Channel | What you need |
|---|---|
| Telegram | Bot token |
| Feishu | App ID + App Secret |
| Discord | Bot token |
| Slack | Bot token + App-level token |
| DingTalk | App Key + App Secret |
Telegram is the easiest place to start.
- Create a bot through
@BotFather - Configure Telegram in
config.jsonor through the CLI - Start the gateway
Example:
mix nex.agent config set telegram.enabled true
mix nex.agent config set telegram.token 123456:ABCDEF
mix nex.agent config set telegram.allow_from 10001,10002
mix nex.agent config set telegram.reply_to_message true
mix nex.agent gatewayOther chat apps are currently better configured directly in ~/.nex/agent/config.json.
NexAgent currently supports:
- Anthropic
- OpenAI
- OpenRouter
- Ollama
The simplest starting points are usually:
- Cloud model: OpenAI or OpenRouter
- Local model: Ollama
Runner handles the agent loop and then dispatches to the selected provider implementation.
Default built-in tools:
readwriteeditlist_dirbashweb_searchweb_fetchmessagememory_writecronspawn_taskskill_listskill_createtool_listtool_createtool_deletesoul_updatereflectupgrade_code
Together, these cover files, shell commands, web access, outbound messaging, long-term memory, scheduling, skill growth, tool growth, and code upgrades.
Custom Elixir tools live in ~/.nex/agent/workspace/tools/<name>/ and are registered as first-class tools.
tool_createcreates a workspace custom tooltool_listinspects built-in and custom toolstool_deleteremoves a custom tool
Beyond tools, NexAgent has a Markdown-based skills system.
Skills are reusable workflow modules that help the agent:
- package workflows
- standardize recurring tasks
- create reusable instructions for itself
Skills live in workspace/skills/<name>/SKILL.md and are exposed to the model as skill_<name> tools.
Code-based capabilities belong in the tool system, where Elixir modules implement deterministic behavior through Tool.Behaviour.
NexAgent sessions are not just short-lived context windows. They are persistent conversations with memory layers behind them.
Sessions are scoped by channel:chat_id, for example:
telegram:123456discord:channel_id
This keeps different chat surfaces isolated instead of blending everything into one conversation stream.
Basic control commands already exist:
/new: start a new session/stop: stop active tasks for the current session
The memory system is layered:
MEMORY.md: long-term memoryHISTORY.md: searchable history- daily
YYYY-MM-DD/log.md: operational memory and accumulated experience Memory.Index: BM25-style retrieval
The point of this design is simple:
- the agent should not start from zero every time
- not everything should be pushed into the prompt
- long-term memory, history, and daily experience should play different roles
This is one of the defining capabilities of NexAgent.
Its evolution does not happen at a single point. It happens in six layers.
SOUL: who the agent is and which long-term principles it followsUSER: who the user is and how the agent should collaborate with themMEMORY: durable facts about the environment, project, and operational contextSKILL: reusable workflows and procedural knowledgeTOOL: deterministic executable capabilitiesCODE: internal implementation upgrades
SOUL.md adjusts behavior, personality, and values.
USER.md captures who the user is, how they prefer to collaborate, and what should stay stable across sessions.
Through MEMORY.md, HISTORY.md, and daily logs, the agent can keep accumulating durable project and environment facts instead of depending only on the current chat window.
Through skill_create, the agent can keep expanding reusable workflows and procedural knowledge.
Through tool_create and workspace custom tools, the agent can keep expanding deterministic executable capability.
The code layer has its own explicit upgrade path:
reflect: inspect module source, history, and diffsupgrade_code: submit updated module codeCodeUpgrade: backup, validate, compile, load, and version codeUpgradeManager: coordinate code upgrades, hot swaps, and rollback paths
That is what makes NexAgent more than a configurable agent. It is an agent system that is explicitly being built to learn, extend, and upgrade itself across multiple layers.
flowchart LR
A["Reflect<br/>Read source / history / diff"] --> B["Understand<br/>Find the problem or opportunity"]
B --> C["Upgrade Code<br/>Submit new code"]
C --> D["CodeUpgrade<br/>Backup / validate / compile / load"]
D --> E["UpgradeManager<br/>Hot-swap / rollback protection"]
E --> F["Agent keeps running"]
NexAgent includes a built-in cron tool for scheduled jobs.
Supported operations:
- add jobs
- list jobs
- enable / disable jobs
- trigger jobs manually
- inspect job status
Supported scheduling modes:
every_secondscron_exprat
To reduce long-running cost, cron execution is deliberately lighter:
- narrower tool scope
- less history
- skipped skill loading in lightweight runs
- isolation from the user’s main session
spawn_task creates a background subagent for an independent task.
It fits cases like:
- long-running work
- parallelizable subproblems
- background tasks that should not block the main session
When it finishes, the result is sent back through the bus.
NexAgent is not a loose collection of scripts. It is a layered, long-running system.
flowchart TB
subgraph L1["Entry Layer"]
A["Chat Apps"]
B["Gateway"]
end
subgraph L2["Agent Layer"]
C["InboundWorker"]
D["Runner"]
end
subgraph L3["Capability Layer"]
E["Sessions"]
F["Memory + Memory.Index"]
G["Tools + Tool.Registry"]
H["Skills"]
end
subgraph L4["Background Layer"]
I["Cron"]
J["Subagent"]
end
subgraph L5["Code Layer"]
K["Reflect + Upgrade Code"]
L["CodeUpgrade + UpgradeManager"]
end
A --> B --> C --> D
D --> E
D --> F
D --> G
D --> H
D --> I
D --> J
D --> K --> L
Another way to read the system is:
- Entry layer: Chat Apps + Gateway
- Agent layer: InboundWorker + Runner
- Capability layer: Tools + Skills + Memory + Sessions
- Background layer: Cron + Subagent
- Six-layer growth model: Soul + User + Memory + Skill + Tool + Code
Core roles in code:
Gateway: manage chat app connection processesInboundWorker: route inbound messagesRunner: build context and execute the agent loopSessionManager: manage persisted sessionsMemory/Memory.Index: manage long-term memory and retrievalTool.Registry: manage tools dynamicallySkills: load and execute skillsCron: manage scheduled jobsSubagent: manage background subagentsCodeUpgrade/UpgradeManager: manage source-level code upgrades
These parts are held together by an OTP supervision tree instead of being scattered across unrelated scripts.
NexAgent already has some important boundaries in place:
- file access is restricted to allowed roots
- path traversal is validated
- shell execution has a whitelist and dangerous-pattern blocking
- chat apps support
allow_from - cron and subagent execution use more restricted paths
It is not finished, but the direction is clear: this is not meant to become an unrestricted local god-agent by default.
If you had to compress the project into one line:
NexAgent is a self-evolving AI agent built on Elixir/OTP for long-running, real-world use.
Its differentiator is not just “one more provider” or “a few more tools.” It is the attempt to combine all of these in one system:
- long-running operation
- chat-app presence
- persistent sessions and memory
- extensible tools and skills
- scheduled jobs and background subagents
- source-level self-improvement
- OTP-driven fault tolerance and hot upgrades
If you care about how agents can keep existing in real environments, not just finish a single demo task, that is the path NexAgent is pushing forward.