An open-source personal learning agent with a layered memory system, a proactive scheduler, multi-channel messaging, and a workspace-scoped Practice Lab β built on the Pi coding-agent SDK without modifying its kernel.
π Homepage: https://hhyqhh.github.io/inno-agent-website/ - project overview, feature walkthrough, and live demos.
π Technical Report: Inno Agent: An Open-Source Personal Learning Agent with Layered Memory, Educational Post-Training, and Local Deployment (arXiv, June 2026) β covers the system design, three-layer memory architecture, instructional-design grounding, and preliminary educational post-training results on Qwen3.6 35B.
π¦ Resource Hub: Chloris-Blaxk/inno-agent-hub β the companion repository containing the skill library, workspace preset templates, and community-contributed resources for Inno Agent.
Inno Agent is a single-learner companion that organizes long-term learning support into three explicit memory layers β an L1 learner profile, an L2 native wiki knowledge base, and L3 session records with cross-conversation retrieval β and wraps them with a learning loop: a cron scheduler, personal IM channels (Feishu / WeChat), and a Practice Lab with an in-browser terminal.
It ships in two forms that share the same runtime/ and workspace/ state:
- Terminal CLI (
inno) β a pure TUI agent, no HTTP. - Web UI (React 19 + Lit + Tailwind 4) β backed by a Node HTTP server with SSE streaming, terminal sessions, a workspace browser, the wiki graph, jobs, skills, and settings.
General-purpose coding agents are optimized for open-ended, context-heavy software engineering, which pushes them toward the largest models and longest context windows. Education is a different optimization target: the tasks are more structured, and the value lies in personalized explanation, misconception diagnosis, exercise generation, feedback, review scheduling, privacy, and low-latency continuous interaction.
Inno Agent takes a different stance:
- Layered memory, not a flat chat summary. Learner state, archived knowledge, and recent dialogue have different lifecycles, so each lives in its own layer with explicit boundaries enforced in the system prompt and storage layout.
- Durable facts go to tools, not replies. Anything that affects future teaching is written to L1/L2 via tools, so personalization decisions are evidence-driven and traceable.
- An open, correctable learner model. The L1 profile is inspectable and editable by the learner; the system prompt forbids unevidenced labels.
- The SDK kernel is never modified. All learning behavior is added through registered tools and a single extension hook (
createInnoExtension), so the agent runtime stays upstream-compatible.
- π§ Three-layer memory
- L1 β Learner profile: goals, knowledge states, misconceptions, and preferences, updated from structured learning events and summarized into a short context pack injected before each turn.
- L2 β Native wiki: human-readable, agent-queryable pages (sources, concepts, entities, analysis) with LLM-assisted summarization, entity/concept linking, and PDF/Office/image ingestion.
- L3 β Session records + cross-conversation retrieval: Pi-SDK session history, indexed into SQLite with threshold-gated lexical recall so relevant past conversations can be surfaced across sessions.
- β° Proactive scheduler β cron-driven background jobs created in natural language, runnable from the agent, the UI, or the cron daemon.
- π¬ Personal IM channels β Feishu (native) plus WeChat (bridge mode), with a unified dispatcher that pushes reminders back out.
- π§ͺ Practice Lab β a workspace-scoped web terminal (xterm.js over WebSocket) with run records the agent can read.
- π Pluggable providers β any
openai-completionsoranthropic-messagesendpoint (Anthropic, OpenAI, DeepSeek, Ollama, or a local model); switch models live in the UI. - π₯οΈ CLI and Web UI β same runtime, same memory, same skills.
- π‘οΈ Optional OS-level sandbox β gate the agent's bash and file operations via pi-sandbox.
- Node.js >= 20.6.0 (cross-conversation L3 retrieval uses the built-in
node:sqlite, available on Node 22.5+; on older runtimes L3 recall degrades gracefully and the rest of the agent runs normally). - npm (workspaces are used; no extra package manager required).
New here? Start with QUICKSTART.md (5 minutes). The short version:
git clone https://github.com/hhyqhh/inno-agent.git
cd inno-agent
npm install # pulls the Pi SDK from npm
npm run build # compiles backend + web
mkdir -p runtime/config runtime/data runtime/skills workspace
cp config.example.json runtime/config/config.json
# Edit runtime/config/config.json and set providers[*].apiKey
npm run server -- --home ./runtime --workspace ./workspace --port 3000Open http://localhost:3000.
Real-world usage guides live in docs/use-cases/.
| Guide | Description |
|---|---|
| Skill Tutorial β Building a Workspace Agent | Use agent.md and .skills/ to build a custom learning agent scoped to a workspace, with a concrete English study example |
Web UI (serves the API and the built frontend):
npm run server -- --home ./runtime --workspace ./workspace --port 3000CLI (terminal agent, no HTTP):
npm run start -- --home ./runtime --workspace ./workspaceDev (backend + Vite HMR on :5173, with /api proxied to :3000):
npm run dev:server # backend
npm run web:dev # frontendSandbox (OS-level isolation of bash/file operations; requires ripgrep):
npm run server:sandbox -- --home ./runtime --workspace ./workspace --port 3000The included restart-dev.sh orchestrates both processes (build, start, stop, status, logs, smoke-test). Run bash restart-dev.sh --help.
runtime/config/config.json (template: config.example.json):
{
"defaultProvider": "innospark",
"defaultModel": "claude-sonnet-4-6",
"providers": {
"innospark": {
"baseUrl": "https://api.example.com",
"api": "anthropic-messages",
"apiKey": "replace-me",
"models": [{ "id": "claude-sonnet-4-6", "name": "Claude Sonnet 4.6" }]
}
},
"server": { "port": 3000 },
"channels": {
"feishu": { "enabled": false },
"wechat": { "enabled": false, "mode": "bridge", "sidecarBaseUrl": "http://127.0.0.1:4319" }
}
}Each provider has a baseUrl, an api (openai-completions or anthropic-messages), an apiKey, and a models[] list. The server hot-rewrites this file when you switch model in the UI.
Both CLI and server resolve paths through apps/inno-agent/src/runtime.ts. Precedence: CLI flag > env var > ~/.inno-agent/....
| CLI flag | Env var | Default |
|---|---|---|
--home |
INNO_HOME |
~/.inno-agent |
--config |
INNO_CONFIG_FILE |
<configDir>/config.json |
--config-dir |
INNO_CONFIG_DIR |
<home>/config |
--data / --data-dir |
INNO_DATA_DIR |
<home>/data |
--skills / --skills-dir |
INNO_SKILLS_DIR |
<home>/skills |
--workspace / --workspace-dir |
INNO_WORKSPACE_DIR |
invocation CWD |
--port |
INNO_PORT (config) |
3000 |
The global skill library and the Simple Mode workspace presets (an agent.md + .skills/ bundle, surfaced as one-click cards on the welcome screen) are both fetched from a remote content hub. By default this is the public GitHub repo Chloris-Blaxk/inno-agent-hub; you can point it at a private GitHub repo or a self-hosted bundle service instead β a config change, no code change.
Configure it in runtime/config/config.json (or via the UI: Settings β Content Hub):
// Or: pull from a self-hosted bundle service (private deployments)
{
"contentHub": {
"type": "bundle",
"baseUrl": "http://localhost:8787",
"token": "" // optional Bearer credential
}
}Presets are downloaded on first use and cached under <dataDir>/preset-cache/; the templates bundled with the app serve as an offline fallback. A legacy github.token is migrated into contentHub.token automatically.
Self-hosting: a zero-dependency local bundle service lives in scripts/content-hub-server/ β back it with your private git repo of skills + templates. See its README for the layout and run commands:
CONTENT_DIR=/path/to/content node scripts/content-hub-server/server.mjsapps/inno-agent/ Backend (CLI + HTTP server), TypeScript -> dist/
apps/inno-agent/web/ Frontend (React 19 + Lit + Tailwind 4 + Vite)
scripts/content-hub-server/ Self-hosted Content Hub bundle service (skills + presets)
runtime/ Local runtime state (config, data, skills) - gitignored
workspace/ Default agent working directory - gitignored
The Pi SDK packages (@earendil-works/pi-ai, @earendil-works/pi-coding-agent, @earendil-works/pi-web-ui) are pulled from npm.
Inno Agent is a single-user system with four layers: user interfaces β application layer β Pi agent runtime β layered memory.
User Interfaces CLI Β· Web UI (React) Β· Feishu Β· WeChat
β
Application Layer Channel adapters Β· HTTP API (SSE) Β· Memory orchestration
Cron scheduler Β· Practice Lab Β· WebSocket terminal
β
Agent Runtime Pi AgentSession Β· registered tools Β· inno extension
(Pi SDK, unmodified) General LLM provider ββorββ distilled educational model
β
Layered Memory L1 learner profile Β· L2 native wiki Β· L3 session records
- Agent core β
@earendil-works/pi-coding-agentprovides the loop. Inno wraps it withapps/inno-agent/src/agent/inno-extension.ts, which registers providers and tools (L1 learner, L2 wiki, L3 recall, scheduler, practice lab) and abefore_agent_starthook that injects the L1 context pack β and, when relevant, threshold-gated L3 recall β into the system prompt. - L1 β learner memory (
src/memory/learner/): evidence-driven profile + event log, summarized into aContextPackper turn. - L2 β wiki memory (
src/memory/l2/): structured wiki pages with frontmatter, links, graph, summarizer, and document ingestion; exposed as agent tools and via/api/wiki/*. - L3 β session memory (
src/memory/l3/+ PiSessionManager): the SDK owns session JSONL files; Inno layers a SQLite index (node:sqlite+ FTS5) on top for cross-conversation recall, surfaced both automatically (above a relevance threshold) and via thel3_recalltool. - Scheduler (
src/scheduler/): cron jobs persisted tojobs.json+runs.jsonl; runnable from the agent (run_scheduled_job), the UI, or the daemon. - Channels (
src/channels/):ChannelRegistrywith Feishu (and bridge-mode WeChat) so reminders can be pushed back out. - HTTP server (
src/server.ts): plain Nodehttp.createServerwith SSE for chat streaming and WebSocket for the in-browser terminal. - Web UI (
web/src/): React 19 + Lit + Tailwind 4. State lives in framework-agnosticEventEmitterstores underweb/src/stores/; REST/SSE calls inweb/src/api/.
The backend API route table and runtime details are in apps/inno-agent/README.md.
A typical production layout separates code, config, data, and workspace:
/opt/inno-agent # this repository
/etc/inno-agent/config.json # config
/var/lib/inno-agent/data # sessions, jobs, memory, downloads
/var/lib/inno-agent/skills # uploaded skills
/srv/inno-workspace # files the agent should work on
INNO_CONFIG_DIR=/etc/inno-agent \
INNO_DATA_DIR=/var/lib/inno-agent/data \
INNO_SKILLS_DIR=/var/lib/inno-agent/skills \
INNO_WORKSPACE_DIR=/srv/inno-workspace \
INNO_PORT=3000 \
npm run serverA Dockerfile and docker-compose.yml are provided as starting points.
Issues and PRs are welcome. Before opening a PR, please run npm run build locally β there is no top-level lint or test runner wired up yet, but the TypeScript build doubles as a sanity check. Keep changes focused, match the existing code style, and update the relevant docs when behavior changes.
Join the WeChat user group to ask questions, share use cases, and follow updates. Scan the QR code below:
MIT.
This project depends on the Pi SDK (@earendil-works/pi-* packages by Mario Zechner), which is also MIT-licensed and consumed via npm.

