Skip to content

gregoryschlepper/NEO

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

108 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

NEO – Personal AI Assistant

NEO is a personal single-user assistant with Telegram as its interface: locally operated, using Anthropic Claude as the dialogue LLM and Ollama for embeddings and supporting tasks. The assistant's visible name in chat comes from persona.assistant_name in config/neo_config.json, not from hard-wired strings in the code.

What is NEO?

NEO is a deliberately narrow Python application for exactly one configured Telegram chat: a slim main chat (neo/turn_orchestrator.py), assist paths in front of it inside the transport layer (neo/telegram_transport.py — web, weather, calendar, mail, reminders, file block), and memory capture afterwards. Web search and weather use fixed, deterministic patterns (no free-form “look something up on the internet” in normal chat). Long-term context lives in persona markdowns under docs/, in cfg["persona"], and in file-based memory (fact files plus a LanceDB derivative). There is no generic tool router inside free chat.

Why NEO exists

NEO emerged as both a technical and a personal agent framework: one built around stable identity, continuity of relationship, and reliable handling of context through clearly separated layers such as persona markdowns, memory, and assist paths.

That leads to a deliberate architectural decision: conversational identity is not controlled through fleeting prompt fragments alone, but through maintained persona documents under docs/ which, together with the persona core (neo/persona_core.py), form a behavioral and character framework. These files are not decorative extras. They are a structural part of the system.

NEO is my first coding project of any kind. For me, that makes it both a real agent project and a learning project. That is also what gives it its character as a deliberate VibeCoding project — not as a gimmick, but as a serious attempt to teach myself architecture, systems thinking, and practical implementation step by step.

What does NEO currently do?

  • Telegram: long polling, focused on one allowed chat ID; commands such as /start, /hilfe, model selection (/haiku, /sonnet), and /neu (see the runbook).
  • Dialogue: Anthropic Messages API; configurable default model; optional prompt caching only through the context fields documented in config/neo_config.json (see config/CONFIG_README.md).
  • Memory: reads and writes through defined targets (people, projects, preferences, rules); retrieval via LanceDB; memory proposals appear after the visible main reply and require confirmation.
  • Web & weather: only through documented text triggers at the beginning of a message (web:, fixed … im web … forms); weather uses a separate shortcut path in neo/weather_detect.py and the same execution layer as web search (neo/web_run.py / Perplexity).
  • Calendar & mail: dedicated detect/run modules; conservative mail sending; draft→send bridge with an optional local alias file (config/mail_family_aliases.json, template .example.json — not versioned; if the file is missing, only recipients containing @ work; invalid JSON produces a clear error when sending through a short alias).
  • Reminders: create / list / cancel within the language corridor described in the runbook; due/send chain via JobQueue.
  • File block (only with paths.file_root set as an absolute path): Stage 1 search, read, and directory listing; Stage 2 move a single file or sort by type with pending state (preview → confirm or abort); Stage 3 D1 “delete” as a move to file_root/.trash/ (no unlink, no folder deletion), also with pending confirmation.
  • Rich docs (read-only): under file_root, including ODT, ODS, DOCX, XLSX, PDF as extracted plain text (see limitations below).
  • Morning Briefing: a chain consisting of system check, weather, calendar, mail, RSS, mb_input.json, and a model run — see docs/RUNBOOK.md.
  • Ollama: embeddings and configured local helper roles; ollama.base_url and model names are part of the operating configuration.

What does NEO intentionally not do?

  • No OCR and no OCR-based text extraction path for images or PDFs.
  • No Office editing and no writing back into rich formats through the file block.
  • No layout or formatting fidelity for extracted documents — only plain text for chat context.
  • No permanent file deletion and no deletion of entire folders; at most a trash move of a single file into .trash/ under file_root, with confirmation.
  • No generic file monolith in free chat: no free editor inside the file tree; the earlier kDrive/router stack was removed (Phase G1). The current file block is intentionally narrow.
  • No group focus, no multi-tenant product, and no central user administration.
  • Images and voice are not developed as core features.
  • No “web search through small talk” outside the documented triggers.

Who is NEO for?

For one operator who manages Linux, Python ≥ 3.10, API keys, and local secrets, and who is willing to maintain persona, memory, and configuration consciously. The public repository provides neutralized persona templates and an example neo_config.json; personal content and live configs do not belong in Git (see docs/RUNBOOK.md → Private MasterZIP / stash, if you need a complete private handover).

Quickstart

Requirements: Python ≥ 3.10, Ollama (local), Telegram bot (BotFather), Anthropic key; Perplexity key for the web and weather path (as expected in secrets/.env).

git clone <repo-url>
cd NEO
python3 -m venv .venv
source .venv/bin/activate
pip install --upgrade pip
pip install -e .

Create example configuration and secrets (replace placeholders with real values):

cp config/neo_config.example.json config/neo_config.json
# optional, for mail draft→send alias resolution:
cp config/mail_family_aliases.example.json config/mail_family_aliases.json

Optional locale in config/neo_config.json sets the local IANA timezone and Morning Briefing weather query/label for wttr.in (defaults remain Berlin / Europe/Berlin if you omit the block). See config/CONFIG_README.md.

secrets/.env (file secrets/.env, not versioned):

ANTHROPIC_API_KEY=<your-anthropic-key>
TELEGRAM_BOT_TOKEN=<your-bot-token>
TELEGRAM_ALLOWED_CHAT_ID=<your-telegram-chat-id>
PERPLEXITY_API_KEY=<your-perplexity-key>

For the additional secret files required for calendar and mail, see docs/RUNBOOK.md (section “Secrets”).

Embedding model for Ollama:

ollama pull snowflake-arctic-embed2

First run (recommended: bootstrap first, then the agent):

source .venv/bin/activate
python3 -c "from neo.bootstrap import bootstrap; raise SystemExit(bootstrap())"
python3 -m neo.mb_systemcheck
python3 main.py

Tests (optional):

pip install pytest
python3 -m pytest tests/ -v

Configuration

  • Fields and blocks of config/neo_config.json: config/CONFIG_README.md.
  • paths.file_root: optional; if empty or missing, the file block responds with a fixed “disabled” message (no silent fallback path).
  • Persona: runtime strings for chat and Morning Briefing come from cfg["persona"]; deeper markdown sources live under docs/ (SOUL.md, HUMAN_LAYER.md, USER.md, AGENTS.md) together with neo/persona_core.py — see docs/ARCHITECTURE.md.
  • Public Git state: docs/USER.md, docs/SOUL.md, and docs/HUMAN_LAYER.md are templates without personal PII; adapt them for your own setup or start from docs/USER.example.md.

Documentation references

Document Contents
docs/RUNBOOK.md Operator path from a fresh host to live Telegram, system checks, Morning Briefing, tools, error patterns, and Public/Private MasterZIP.
config/CONFIG_README.md Explanation of neo_config.json blocks including file_root, prompt caching, and mail aliases.
docs/CHANGELOG.md Decision and release history (Phases A–G, file block, documentation).
docs/ARCHITECTURE.md Persona vs. memory, derivative model.
docs/AGENTS.md Operational rules for the agent persona (without repeating SOUL/HUMAN).

Project structure (short overview):

NEO/
├── config/              # neo_config.example.json, mail_family_aliases.example.json
├── scripts/             # e.g. capture_private_release_stash.sh, build_masterzip.sh
├── secrets/             # .env and other secrets (gitignored)
├── docs/                # Persona, RUNBOOK, CHANGELOG, ARCHITECTURE
├── neo/                 # Application code
├── data_logs/           # Runtime data (gitignored)
├── patches/             # Optional MasterZIP / build artifacts (often gitignored locally)
├── tests/
├── main.py
└── README.md

Release and project status

The authoritative sources for behavior and reconstruction are the Git state of this repository plus your local config/neo_config.json and secrets. MasterZIP artifacts under patches/ are optional snapshots (see docs/RUNBOOK.md → Public vs. Private, build scripts).

Phases in short (detailed operational view: runbook):

Phase Contents
A Turn orchestrator extracted; transport decoupled from free-chat control.
B Memory capture moved out of the main chat prompt; confirmation is now a separate step.
C Telegram main-chat prompt slimmed down; web and Morning Briefing no longer share the same inflated rule block as free chat.
D Web intent and execution removed from the transport; detection is deterministic, with no LLM fallback for trigger selection (D-v1).
E Calendar and mail detectors moved out of the old path into dedicated modules; conservative mail sending; draft→send bridge and family aliases only in the mail-sending path.
F Reminders as an assist path: create/list/cancel in a narrow corridor; due/send chain unchanged.
D.x Weather: narrow patterns in weather_detect.py; on a match, the same run_web_search path as explicit web search — no broadened general web matching.
G Product cleanup (G1–G4): the old stack was removed — kDrive/document router, soft notes, soft_notes in memory (see docs/CHANGELOG.md). S1–S3/R are a new, narrow file path.
S1 File block Stage 1: search, read (text + rich formats as plain text), directory listing; only with paths.file_root; no content editing.
S2 File Stage 2: move a single file, sort a folder by type — preview, explicit confirmation, abort.
S3 File Stage 3 D1: “delete” as move to file_root/.trash/; no permanent deletion, no folder deletion.
R1–R3 Rich-doc reading: ODT, ODS, DOCX, XLSX, PDF — no layout fidelity, no OCR, no LibreOffice requirement.

Web triggers (D v1): after strip() and casefold(), only at the beginning of the message: web: …, suche im web nach|zu|über …, recherchiere im web nach|zu|über …. Phrases such as “such mal nach …” without these patterns remain in free chat.

Model selection: technically, NEO is not hard-wired to a single model; for the documented persona and quality target, Claude Sonnet (and at the top end Opus) are the reference — see the runbook and your anthropic.* entries in neo_config.json.

License

NEO is licensed under the Apache License 2.0.

In short, that means the code may be used, modified, and redistributed, including in commercial contexts, as long as the license terms are respected. The authoritative source is the full license text in the LICENSE file.

What matters here is the separation between project code and operating environment: the license of this repository covers the code and the project files included here, but does not automatically cover external models, APIs, services, trademarks, or third-party terms of use.

About

A personal AI agent built from scratch: identity-aware chat, memory, reminders, mail/calendar assistance, web search, and a narrow file assistant.

Topics

Resources

License

Stars

Watchers

Forks

Packages