Local-first personal agent with UI + API, auditable learning, and retrieval over your own knowledge.
Quick Start • Installation • Run Modes • API & Integration • Docs
{hatori} is an offline-first assistant platform designed for two-way operation:
- You chat with
{hatori}in the local UI (23571) and teach through real interactions. - External apps call the API (
23572) to ingest content, request replies, and report delivery outcomes (sent_as_is/edited_then_sent) so{hatori}learns from what was actually sent.
Core capabilities:
- Local UI chat and history
- API-first integration for upstream apps
- RAG pipeline with PostgreSQL +
pgvector - Auditable learning loop (
learning_events,delivery_events) - Model gateway strategy (MLX preferred, Ollama fallback)
- Localhost-first security and collision-safe service orchestration
- Local and private by default
- No hidden cloud dependency for base operation
- Reliable ingestion/reply/outcome loop for “learn from real sends” behavior
- Clear contract for integrations (idempotency + auth + rate limits)
git clone https://github.com/moldovancsaba/hatori.git
cd hatori
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -r ui/requirements.txt
./tools/scripts/hatori_env_init.sh
make runOpen:
- UI:
http://127.0.0.1:23571/chat - API health:
http://127.0.0.1:23572/v1/health
Required:
- Python 3.11+
- Docker engine (or Colima on macOS)
- Bash-compatible shell
Optional:
- Ollama (recommended local generator fallback)
- MLX-LM (Apple Silicon MLX backend)
- Node.js (for
clients/hatori-clientexamples)
Create local env + token:
./tools/scripts/hatori_env_init.shFile created:
~/.config/hatori/hatori.env(permissions:600)
Default keys include:
HATORI_API_TOKENUI_PORT=23571API_PORT=23572HATORI_GENERATOR_ORDER=mlx,ollama
make upThis starts local Postgres (pgvector/pgvector:pg16) container hatori-pg.
make runStarts/reuses DB + API + UI with safe port ownership checks.
make install-service
make service-status
make service-logsStop only {hatori} listeners:
make stopUninstall:
make uninstall-servicemake install-HatoriMenubar
make run-HatoriMenubarApp path:
~/Applications/HatoriMenubar.app
Canonical API contract:
Integration guide for external apps:
Local operations runbook:
GET /v1/healthPOST /v1/agent/respondPOST /v1/agent/feedbackPOST /v1/agent/outcomePOST /v1/ingest/eventPOST /v1/artefacts/uploadPOST /v1/artefacts/ingest_path(default disabled)GET /v1/search
/v1/agent/respond safety behavior:
- if local model output is unavailable/unsafe/internal-scaffold, API returns a deterministic send-ready fallback text instead of surfacing model error text to integrators.
Current stable contract is HTTP-only. No public WebSocket endpoint is exposed in v1.
- Default bind:
127.0.0.1 - API write auth:
X-Hatori-Token(HATORI_API_TOKEN) - Idempotency keys:
- ingest:
external_event_id - outcome:
external_outcome_id
- ingest:
- Token-scoped rate limits on key endpoints
- Collision-safe startup:
- reuse if
{hatori}already owns the port - refuse if foreign process owns the port
- never kill non-
{hatori}services
- reuse if
- Service ownership rule:
- if UI/API were started manually (
python -m uvicorn ...), launchd service mode reports them as foreign owners. - use
make stopthenmake install-serviceto return to service-managed operation.
- if UI/API were started manually (
Run full suite:
make testRun planning gate:
./tools/scripts/planning_check.shRun integration smoke:
make reply-smokeRun strict integrator acceptance gate (ingest/respond/outcome + idempotency + auth):
make integration-acceptanceCurrent version:
v0.8.5(fromVERSION)
Release and SemVer policy:
Rule summary:
- Patch: fixes/docs/non-breaking internal updates
- Minor: backward-compatible features
- Major: breaking changes
api/- API serviceui/- UI servicehatori/- core runtime and adapterspks/- schema and migrationstools/- scripts, launchd, menu app toolingtests/- golden tests and fixturesdocs/- product, architecture, API, runbooksclients/hatori-client/- minimal TypeScript integration client
- Overview:
docs/00-overview/README.md - Architecture:
docs/02-architecture/architecture.md - Data/PKS spec:
docs/03-data/pks-spec.md - API contract:
docs/10-api-contracts/hatori-api-v1.md - Integration kit:
docs/12-reply-integration/README.md - Security/threat model:
docs/05-security/threat-model.md - Evaluation:
docs/06-evaluation/golden-tests.md - Menu guide:
docs/07-runbooks/menu-user-guide.md - Planning SSOT:
docs/11-roadmap/README.md
- Fork the repository
- Create a feature branch
- Run:
make test./tools/scripts/planning_check.sh
- Open a PR with verification output
No license file is currently included. Add a license before broad redistribution.
One-command local bootstrap:
make bootstrapThis performs:
- env + token initialization (
~/.config/hatori/hatori.env) - venv creation and dependency install
- DB startup and reset
- Ollama model pull for configured routes
- service install and status check
Additional helpers:
make models-pull # pull all route models from env
make doctor # environment + service diagnostics{hatori} now supports true per-task routing with primary + fallback model lanes.
Default route map in hatori.env:
- Writer lane (
reply_write,plan_write,rewrite_polish):- primary:
mlx(Apertus model id inHATORI_ROUTE_*_MODEL) - fallback:
ollama:gemma2:2b
- primary:
- Drafter lane (
classify_intent,extract_fields,context_pack,retrieval_query_build,edit_pattern_cluster):- primary:
ollama:granite4:350m(IBM Granite Nano — lightest) - fallback:
ollama:gemma3:1b
- primary:
- Judge lane (
answer_score,quality_gate):- primary:
ollama:llama3.2:3b - fallback:
ollama:gemma2:2b
- primary:
Core implementation points:
- task router:
hatori/model.py(get_task_model_adapter(task)) - UI/API use per-task routes for planning and reply generation
- drafter context pack is internal-only and injected into prompt context
Environment keys are generated by:
tools/scripts/hatori_env_init.sh