On this page

HANDOFF.md

Handoff

Aegis Terminal — Handoff

Last rewritten: 2026-09-25 Project root: ~/Documents/Aegis-Terminal (git repo, branch master) Machine: ambassadorcrimson-node — Ubuntu 26.04, kernel 7.0, GNOME on Wayland

This file holds the stable facts: what Aegis is, how it fits together, the rules, and how to run it. Live facts (memory, services, git state, doc counts, recent logs) come from ./aegis-handoff, which bundles this file with a fresh system snapshot. Any AI working on Aegis should read the bundle, not just this file.

Related docs:


1. What Aegis is

A local-first question-answering engine with a desktop app and voice:


2. Hardware limits and the 2026-09-25 crash (read this first)

Measured memory per component (2026-09-25):

ComponentMemoryNotes
Kokoro TTS server~950 MBResident from boot (systemd user unit); mostly swapped when idle
Ollama model qwen2.5:1.5b loaded~1.2–1.5 GB940 MB on disk; stays loaded AEGIS_OLLAMA_KEEP_ALIVE (5m; the Handshake "AI keep-alive" setting) after last use
Ollama daemon idle~20 MBSystem service, starts at boot
Backend (uvicorn, idle)~105 MBGrows with queries / DuckDB cache
Artemis worker (Vosk, 2 recognizers)~160 MB
Desktop GTK + WebKit processes~200–350 MBEstimate, not measured (measuring it is what crashed the host)
Cursor (all processes)~2.5 GBEnough on its own to push the host into swap

What that means:


3. Processes and ports

ProcessPortRuns fromStarted by
Backend uvicorn main:app8000.venv (Python 3.12)systemd user unit aegis-backend.service at login (./aegis-service); otherwise desktop.py (or aegis-lite, or manual)
Kokoro TTS kokoro_server.py5050.venv-kokoro (Python 3.12, CPU torch)systemd user unit kokoro-server.service; ./aegis falls back to spawning it
Ollama11434system installsystem service ollama
Desktop desktop.py—/usr/bin/python3 (system; GTK/WebKit bindings)./aegis
Artemis worker artemis_worker.py—.venv (vosk)desktop.py subprocess; mic via arecord -D plughw:0,7

Kokoro endpoints: POST /speak (plays via aplay, blocks until done), POST /synth (returns WAV bytes). Backend KOKORO_URL must be /synth.

Two Python environments on purpose: .venv (backend, vosk) and .venv-kokoro (torch/kokoro, pinned). The desktop uses system Python because GTK/WebKit introspection bindings live there. Do not merge venvs.


4. Entry points

CommandWhat it does
./aegisFull desktop session: pre-flight, ensures Kokoro, prints memory, launches desktop.py (which starts the backend and Artemis). Logs to logs/aegis-<ts>.log + logs/latest.log.
./aegis-liteTerminal REPL against the backend (starts backend if down).
./aegis-lite "what is X"One-shot query.
./aegis-lite --sozSOZ trainer TUI (curses).
./aegis-lite --healthBackend health.
./aegis-activateVoice-first activation sequence (greeting, Kokoro, backend).
./aegis-handoffBuild the AI handoff bundle (see AI_PROMPT.md).
./aegis-checkRequirements check: OK / WARN / MISSING with a fix per item. --fix runs user-level fixes, --quick, --json. ./aegis runs the quick check at start (AEGIS_SKIP_CHECK=1 skips it).
./aegis-shareExport the knowledge (all DuckDB tables as Parquet + mobile pack + settings) and serve it once on the LAN; --out DIR --no-serve writes it to a folder (section 16).
./aegis-import SOURCERebuild data/aegis.duckdb from an aegis-share URL, .tar.gz or folder, with a backup (section 16).
./aegis-transferBuild ~/Desktop/aegis-transfer/, the hand-carried folder that updates another laptop (section 16).
./aegis-updateRun on the other laptop (from the transfer folder): sync an old install to the bundle's commit, with backup and rollback.
http://127.0.0.1:8000/handshakeHandshake page: handoff bundle, live tests, storage inventory, settings and permissions (section 14). Red button on the launcher; voice "open handshake" / "open settings".
mobile/run-desktop.shAegis Mobile in a phone-shaped window on the laptop (section 15).
mobile/build-apk.shBuild the Android APK for the Tank 3 Pro. Close Cursor first (section 15).
./aegis-serviceThe backend login service: install, uninstall, status, pause CMD (stop, run CMD, start), logs [N] (section 17).
./handshake.shShort read-only briefing (git, backend, DB, bug headers).
~/aegis_start.sh, ~/aegis_shutdown.sh, ~/aegis_full_test.shOlder lifecycle scripts in $HOME (see TRANSFER.md).
/usr/local/bin/speak "text"Say text through Kokoro from any shell.

5. Query pipeline (main.py → POST /query)

Request: {"prompt": "...", "sense"?: ..., "session_id"?: ...}. Order of handling:

  1. User corrections lookup — a user-taught answer wins instantly.
  2. Terminal sense resolution (req.sense or multi-token subject).
  3. Per-query response cache (5 min).
  4. Disambiguation gate (whitelist in config.AMBIGUOUS_SUBJECTS) → status: "ambiguous" + options.
  5. Teach short-circuit ("teach me X").
  6. Fast paths: math, units, stock, weather, currency, time zone.
  7. Wiktionary / definition seed (definition_path.py).
  8. Local BM25 search over DuckDB FTS (local_search.py).
  9. Web expansion (DDGS search + trafilatura/Jina fetch, Firecrawl fallback) — web_ingest.py. Runs only when local hits are missing, cover ≤ 50% of the query words, or the question is "fresh". A definition with ≥ 90% coverage skips it, and so does a "short question" (≤ 4 words, no current-info terms) whose local hits answer it: local_first.local_answer_suffices wants ≥ 90% coverage and a top local sentence holding every query word plus the kind of value asked for (date, number, name). If extraction then finds nothing, the forced web search still runs.
  10. Extractive QA (extractive_qa.build_answer): sentence scoring; strip_markers() removes [N] citation markers, date prefixes, source notes, and leading paragraph numbers.
  11. LLM synthesis (synthesis.py), only if AEGIS_QUERY_ALLOW_LLM is on and synthesis.ram_ok(): - Conversational system prompt; top 3 extracts (280 chars each) as "Source: Title". - Token budget: 320 for how-to, 110 otherwise; hard time cap AEGIS_LLM_CAP_S (15 s) with socket-level cancel. - Rejects answers containing numbers not present in any retrieved text (grounding = extracts + local bodies + web snippets). - "NO ANSWER" or ungrounded → honest no-answer line (answer_qtype: no_answer). - Timeout / low RAM → natural fallback: best 1–2 clean extract sentences.
  12. _sanitize_query_output decorator strips any leftover markers (skips computed/stock/units qtypes).

Response shape: answer, answer_qtype, results, local_hits, web_hits, session_id; ambiguous responses carry status + options[]. The UI shows answer text without numbers and keeps the source list.


6. Voice and Artemis


7. Key modules

FileLinesRole
main.py~3760FastAPI app: routing, /query pipeline, ~70 routes (query, ingest, trainer, facts, voice, exit, debug)
synthesis.py~830Ollama synthesis: prompt, budgets, grounding checks, ram_ok(), streaming with cancel
extractive_qa.py~510Sentence splitting/scoring, strip_markers(), build_answer()
local_search.py~260DuckDB BM25 search
web_ingest.py~1050Web search/fetch/ingest, Wiktionary/Wikipedia seeding
definition_path.py~265Definition-shaped queries
query_expand.py~170LLM search-query expansion
query_log.py~245Structured query log (@query_log.wrapper)
extract.py~690Regex fact extraction
teach.py, tutorials.py~880, ~900"Teach me" tutorials
config.py~125Runtime config (reads AEGIS_* env)
desktop.py~1220GTK/WebKit wrapper, backend start, Artemis bridge, speech queue, answer and control channels
artemis_listen.py~560Wake word + command/question state machine
artemis_worker.py~50Subprocess wrapper: JSON lines out, pause/resume on stdin
voice_commands.py~190Phrase → action parsing (parse, parse_artemis_command, parse_run_query)
voice_stt.py~110Vosk model loading / transcription
kokoro_server.py~135Resident TTS server
narration.py~200Shield of Zeus narration lines
app_exit.py~160Full stack exit (backend, desktop, voice, mic)
aegis-lite.py~155Terminal client
soz_tui.py~330SOZ trainer TUI
settings.py~215User settings: data/settings.json, metadata, startup precedence, live apply (stdlib-only; imported by backend and desktop)
system_report.py~630Handshake data: live status, storage inventory, query/trainer stats, query and trainer self-tests, mic devices and mic test
handshake_routes.py~180APIRouter for /handshake, /system/, /settings (mounted in main.py)
templates/handshake.html, static/aegis-handshake.{css,js}Handshake page
templates/index.htmlQuery engine page
templates/soz.html, static/SOZ pages, theme CSS/JS, fonts (local, no CDN)
mobile/Aegis Mobile: standalone Android app, engine and pack exporter (section 15)

Clutter to ignore: .bak, .pre-.<digits>, main.py.debug., main.py.gates-disabled-, the empty file named =, aegis-fix-*.sh (old one-off patches), archive/.


8. Environment variables (defaults)

Backend / answers:

Desktop:

Voice:

Artemis:

./aegis-handoff prints the live list grepped from the code.

Several of these are also user settings (section 14). Startup precedence: env var set at launch → data/settings.json → default.


9. Data and logs


10. Safe operations

Check memory first:

free -m

Backend as the login service (installed 2026-10-03; section 17):

./aegis-service status # state, memory, /health systemctl --user restart aegis-backend # or ./restart.sh ./aegis-service pause CMD ... # stop it for CMD (DuckDB writes, fix scripts), then start it ./aegis-service logs 100

Backend only, by hand (when the service is not installed):

cd ~/Documents/Aegis-Terminal fuser -k 8000/tcp 2>/dev/null; sleep 1 nohup .venv/bin/uvicorn main:app --host 127.0.0.1 --port 8000 > /tmp/aegis-backend.log 2>&1 & for i in $(seq 1 30); do curl -sf -m 1 localhost:8000/health && break; sleep 1; done

Stop a backend started by hand (never the service: systemd would restart it after 30 s):

fuser -k 8000/tcp

Test a query without the desktop:

./aegis-lite "what is the capital of france" curl -s -X POST localhost:8000/query -H 'Content-Type: application/json' -d '{"prompt":"what is hydrogen"}' | head -c 600

Kokoro:

systemctl --user status kokoro-server --no-pager | head -5 systemctl --user restart kokoro-server

Full shutdown: the Exit button in the desktop, or curl -s -X POST localhost:8000/app/exit.

Tests:

.venv/bin/python full_test.py # needs backend running (git pre-commit hook runs it if up)

Do not use pkill -f <pattern> with broad patterns — it can match and kill the shell running the command. Use fuser -k 8000/tcp or exact PIDs.


11. Non-negotiables

  1. Check free -m before starting anything heavy. Never run ./aegis with Cursor or a browser open.
  2. Stop the backend before opening DuckDB in write mode (single writer).
  3. Verify port bind / /health after every restart.
  4. Back up every file before patching it: .aegis-doctor/backups/<feature>-<timestamp>/.
  5. Patch with exact-match replacement (assert the old text occurs exactly once); no blind sed -i on main.py.
  6. Verify every patch: python3 -m py_compile <file> / bash -n <script>, then a targeted test.
  7. One patch per step; commit after each verified fix (git commit), so git diff / git revert work.
  8. Sample before delete. Never delete data without a backup.
  9. Log every fix/feature in BUGS.md using its existing format (newest at top).
  10. Don't print or paste secrets: never cat .env, never dump env, never paste full ps args.

12. Recent work (from BUGS.md)


13. Open issues


14. Handshake page, live tests, settings

Open it from the red Handshake button on the launcher, by voice ("open handshake", "open settings"), or at http://127.0.0.1:8000/handshake (works in a normal browser too; Artemis switches only work inside the desktop). Tabs (URL hash selects one, e.g. /handshake#settings):

TabWhat it shows / does
HandshakeBuilds the ./aegis-handoff bundle (optionally with a DB and storage section), shows leak-check result, size and parts, sectioned viewer, Copy all / Copy part N / Open folder.
SystemMemory, swap, load, AI-ready gauges; services (backend, Kokoro, Ollama, Artemis, desktop, heavy apps); biggest processes; versions/git; warnings. Refreshes every 5 s.
Query EngineLive self-tests (math, conversion, correction, fact, definition, local search, optional web and AI) with answer, stage and time; the 12-stage pipeline with how many logged questions each answered; speed by answer type (typical/avg/p95/max); questions per day; recent questions.
TrainingRead-only trainer tests (queue, draft-time estimate, fact extraction dry run, correction hit/miss, fact lookup); the report → draft → review → train → facts → corrections flow; queue counts, categories, top corrections, recently trained.
StorageEvery file group Aegis keeps (DB, WAL, jobs, corpus, logs, models, venvs, HF cache, Ollama models, backups, handoff output, git, source) with sizes; per-table rows and text bytes with descriptions; docs by source; facts by attribute; the DB-bloat finding. Cached 10 min; "Re-measure" refreshes.
Settings & PermissionsSwitches and sliders from settings.py (below), mic device picker, 3-second mic test with level meter and Vosk transcript.

Settings (data/settings.json; env var at launch wins at startup):

KeyEnv varDefaultApplies
mic_allowed—onnow (backend 403s, desktop stops Artemis)
mic_deviceAEGIS_MIC_DEVICEplughw:0,7when Artemis restarts (desktop restarts it)
voice_output—onnow
speak_answers—offnow
internetAEGIS_QUERY_ALLOW_WEBonnow
local_aiAEGIS_QUERY_ALLOW_LLMonnow
artemisAEGIS_ARTEMISonnow (desktop only)
ai_warmup—onnext launch
ai_min_free_mbAEGIS_LLM_MIN_FREE_MB1600 (600–3000)now
ai_cap_sAEGIS_LLM_CAP_S15 (5–60)now
ai_keep_alive_minAEGIS_OLLAMA_KEEP_ALIVE5 (0–30 minutes; 0 unloads after each answer)now
curious—onnow (section 17)
curious_min_free_mb—800 (300–3000)now
fullscreenAEGIS_FULLSCREENonnext launch

desktop.py passes settings.env_for_backend() to the backend it starts. A backend started by hand (section 10) doesn't set AEGIS_QUERY_ALLOW_LLM, so AI answers are off there unless you switch "Local AI model" on.

Endpoints (handshake_routes.py):

Test safety:


15. Aegion, the Aegis app (formerly Artemis / Aegis Mobile)

Refreshed 2026-10-03 for the one-app merge (section 20 has the details). Aegion is the same Kivy app (mobile/main.py) on Android, iPhone/iPad (kivy-ios, mobile/BUILD-IOS.md) and the Linux, macOS and Windows desktops (./aegis, mobile/RUN-DESKTOP.md). The display name is Aegion; the package id stays online.mindflux.aegis and the App class stays AegisMobile, so updates keep the data folder (.../aegismobile). Artemis is now only the wake word. Version 0.2.0 (buildozer.spec, app_version.txt).

Target phone: Unihertz Tank 3 Pro. It runs Android 15 (API 35), has 16 GB RAM, a MediaTek Dimensity 8300 (arm64-v8a) and a 1080x2460 screen at density 3.0 (360x820 dp; status bar and camera hole 110 px, no bottom inset with gesture navigation).

What it is:

Files (mobile/):

FileRole
main.pyKivy UI (Shield of Zeus crimson/gold theme)
engine/mathx.py, units.py, extractive.pyCopies of math_compute.py, units.py, extractive_qa.py; build-apk.sh re-copies them before every build
engine/factq.pyMirrors main._parse_fact_query / _format_fact_answer and definition_path.classify; change both sides together
engine/pack.pyPack reader: corrections, facts (+aliases), definitions, BM25 over packed postings
engine/textutil.pyTokenizer shared by the exporter and the engine
engine/llm.pyOptional Ollama client (urllib)
export_mobile_pack.pyLaptop only: DuckDB (read-only) → assets/aegis-pack.sqlite
buildozer.specarm64-v8a only, android.api = 35, minapi = 26, accept_sdk_license = True, requirements = python3,kivy==2.3.1,sqlite3,plyer, permission INTERNET (local AI only)
build-apk.shGuards (refuses with Cursor running or under 2000 MB free), engine sync, optional export, laptop self-test, buildozer android debug with Gradle capped at 1 GB and one worker; copies the APK to mobile/dist/
run-desktop.sh [--shots]Runs the app in a 408x906 window; --shots saves screenshots of every screen via desktop_shots.py
make-spec-html.pyBuilds handoff-out/aegis-mobile-build.html (copied to ~/Desktop), a self-contained page with every mobile/ file, the pack, an extractor, build/verify/install steps and a Cursor prompt, so another machine can build the APK; --no-pack leaves the private pack out

Knowledge pack (assets/aegis-pack.sqlite, git-ignored, rebuilt on demand):

fuser -k 8000/tcp .venv/bin/python mobile/export_mobile_pack.py

Build (on this laptop):

  1. Close Cursor and browsers.
  2. Free RAM: systemctl --user stop kokoro-server; fuser -k 8000/tcp.
  3. Run mobile/build-apk.sh (add --export to refresh the pack first).

Install on the Tank 3 Pro:

  1. Connect USB and choose "File transfer".
  2. Copy the newest mobile/dist/aegis-mobile-<version>-arm64-v8a-debug.apk (the version is in mobile/buildozer.spec) to the phone's Download folder.
  3. On the phone, open Files and tap the APK. When Android 15 asks, allow Install unknown apps for the Files app (Settings → Apps → Special app access → Install unknown apps).
  4. Tap Install, then open Aegis.

Optional local AI on the phone (Termux from F-Droid):

pkg install ollama ollama serve & ollama pull qwen2.5:1.5b

Then in Aegis go to Settings, switch on "Use local AI", and tap "Test AI connection".

Performance on the laptop (the phone should be similar or faster):

Tutorials page (2026-09-27; see BUGS.md):

Tutorial trainer, navigation and tutorial facts (2026-09-27, 0.1.16; see BUGS.md):

Go deeper, tutorial levels (2026-09-27, 0.1.16; see BUGS.md):

Shield of Zeus in the background (2026-09-27, 0.1.17; see BUGS.md):

Styles, restart to apply, honest boot (2026-09-27, 0.1.17; see BUGS.md):

Carrier phrases and clause superlatives (2026-09-27; see BUGS.md):

Local first (2026-09-27, 0.1.17; see BUGS.md):

Out of scope for now:

The old prototypes (a Kivy UI over a toy HTTP bridge with a 3-document corpus and phi3) are in archive/mobile-prototype/.


16. Updating another machine (transfer folder)

The user's second laptop has an older install. It is updated from a folder carried by hand. The user copies it to ~/updates/aegis-transfer there, and an agent follows its START-HERE.md.

Build it here (the repo must be committed; it takes about 25 s, ~24 MB, ~120 MB RSS; the backend can stay up):

./aegis-transfer # recreates ~/Desktop/aegis-transfer/ cp -r ~/Desktop/aegis-transfer /media/$USER/<drive>/

Contents:

PathWhat
START-HERE.mdStep-by-step guide for an agent that knows nothing; rendered from transfer/START-HERE.md
repo/aegis.bundle, repo/aegis-code.tar.gzgit bundle --all (every ref and tag) and git archive HEAD
knowledge/aegis-share --out: one Parquet file per table, manifest.json, extras/ (mobile pack, settings), aegis-import
python/pip freeze of .venv / .venv-kokoro (used as -c constraints) and interpreter versions
system/, mobile/, handoff/, tools/Kokoro unit and speak; APK build page with BUILD-GUIDE.md and extract_aegis.py; a fresh aegis-handoff --db with the docs; aegis-update, aegis-import, aegis-check, the pre-commit hook
MANIFEST.json, SHA256SUMSSource commit, time, sizes, row counts; checksums of every file

Safety:

On the other laptop, START-HERE.md runs these steps in order:

  1. sha256sum -c.
  2. Find the install (default ~/Documents/Aegis-Terminal; otherwise ask the user).
  3. Stop Aegis.
  4. aegis-update --dry-run, then the real run. It backs up the code and .git to .aegis-doctor/backups/update-<ts>/ with a rollback.sh and moves git to the source commit. Old-only files stay unless the user chooses --delete-old-only, which moves them into the backup.
  5. pip installs with the freeze as constraints.
  6. ./aegis-import "$T/knowledge", which replaces the DB after moving the old one into a backup.
  7. ./aegis-check --fix, asking before each fix. Sudo fixes go to the user.
  8. The system/ files, with approval.
  9. Verify: health, full_test.py, the Handshake tests.
  10. The APK (Python 3.11, buildozer 1.6.0, Cython 0.29.37, Kivy 2.3.1; WSL2 on Windows).

Regenerate the folder after any commit that should reach the other laptop. MANIFEST's source_commit must equal HEAD.


17. Curiosity engine (learns by itself, laptop and phone)

Aegis finds subjects in everything it reads, ingests each real one directly, and asks checked questions only for facts still missing. Shared logic: mobile/engine/curiosity.py (stdlib only; the laptop loads it by path). Tests: mobile/test_curiosity.py, mobile/test_autotrain.py, test_curious.py.

Relevance rule, no LLM: a question is asked only when

  1. the subject is real: an English Wikipedia article with a Wikidata item (disambiguation pages, lists, years and dates are dropped by one batched wbgetentities lookup per 50 titles);
  2. the fact exists: one question per property the item has (PROPERTY_QUESTIONS: born, died, capital, population, elevation, area, founded, founder, inventor, creator, country, mass, orbital period), plus "what is X";
  3. Aegis found it: in a page it saved, an answer, a tutorial, a Wikipedia lead section, or an item-valued fact it kept, at most 2 steps from your questions or what it already knows;
  4. cross_check agrees with the Wikidata value (years equal, numbers within 2%, population 10%, names named). A disagreeing answer is not kept and is logged.

Sources: the Wikipedia API (extracts, lead links), the Wikidata API and the free Wikipedia daily feed. No keys, no paid APIs. Seeds: your questions, your misses (laptop: query_log and pending /reports), the feed (only while fewer than 20 topics wait).

Direct ingestion first: each real subject's article is compared claim by claim with its Wikidata facts. Confirmed (the article states it) is stored with both sources; pending (the article doesn't say) waits for review on the laptop and is not kept on the phone; contradicted is dropped and logged. Only the properties still missing are asked.

Laptop (curious.py, a thread in the backend):

Phone (Auto-train, needs 0.1.19): a curious job after follow-ups, every second question, under every Auto-train gate and cap (so only while charging in the background by default). Setting auto_curious (on). Direct ingestion keeps confirmed facts and the article's lead as auto records; ingest.MAX_AUTO is 10,000 (about 5 MB), shown as "of which Auto-train facts" in Storage and cleared from Settings. Trainer card: "Curious: N topics waiting · K facts kept, D disagreed".


18. Shared archive (every phone, one server)

Every Aegis phone downloads one archive of checked facts. Phones whose users agree help build it. Server: server/ (PHP 8, PDO MySQL; server/README.md has install, cron and the API). Phone: mobile/engine/archive.py (stdlib only). Tests: server/tests/test_check.php, server/tests/test_api.php (--mysql DSN USER PASS on the real database), mobile/test_archive.py.

Phones point, the server fetches. A contribution is {qid, title, pids, about} plus a random device id and token from v1/register. Questions, answers, teachings and anything typed are never sent. verify.php (cron, every few minutes) fetches the Wikidata entity and the Wikipedia intro itself and runs lib/check.php, a port of curiosity.check_article that must stay in step with it (tests/make_vectors.py rebuilds the vectors from the phone's Python). Only values from the server's own fetch are published; a value that later fails a re-check (after 90 days) is withdrawn, and the withdrawal syncs.

Downloading is private: v1/facts?since=SEQ (delta sync, every 6 h under Auto-train's gates) and v1/bucket/XXXX for a name not on the phone. XXXX is the first 4 hex digits of the sha256 of curiosity.norm(name), so the server never learns the name or the question.

Trust: refs are accepted, rejected (contradicted, not a real subject, no such claim) or unconfirmed (no article, a redirect, not stated); agreement counts devices. A device with at least 50 refs, over 60% of them rejected, is suspended (403 on the phone stops contributing). Rate limits are in config.php limits. admin.php withdraws facts and suspends or restores devices.

Phone:

Deploying:

  1. Copy server/ to the web host and create the database with schema.sql.
  2. Copy config.sample.php to config.php and fill in the database, salt, cron_key and admin_password_hash.
  3. Add the cron line for verify.php.
  4. Run php tests/test_api.php --mysql ... once.
  5. Put the URL into ARCHIVE_URL, or into the phone's setting.

19. Signal Walk inside Aegis (one APK)

Signal Walk logs Wi-Fi, Bluetooth and cell towers along a GPS walk. It is native Kotlin, and p4a cannot compile Kotlin, so it ships as a prebuilt Android library that buildozer merges.

Voice (Artemis), with or without the wake word, or typed on the Ask page:

Aegis Engine questions (engine/signalwalk.py, stage "Signal Walk", qtype signalwalk, chip SIGNAL WALK). This stage comes right after your own teachings, before every other stage:

Ask Artemis button: the walk screen's header shows ASK ARTEMIS only inside Aegis (AegisBridge.hosted). It sets AegisBridge.requestAsk() and finishes. If the walk screen is alone in its task, it first starts Aegis. main.py on_resume → _signal_walk_back() reads takeAsk(), opens the Ask page and calls listen(send=True). The question heard is asked, and its answer is read aloud.

Pause and resume: while Signal Walk is on top, Kivy is paused. on_pause stops Artemis's recognizer first, then any Voice-button dictation; on_resume turns Artemis back on. A walk runs in WalkService, a foreground service (location and connected device) in the app's main process. It is independent of the Shield of Zeus service (:service_shield process, dataSync), so handing the data to the Shield service does not touch it. Closing Aegis with "exit" may end the app's process, and with it a walk in progress (not tried on the phone); say "stop the walk" first.

After changing the Kotlin (AegisBridge.kt, MainActivity.kt, WalkFragment.kt, fragment_walk.xml in ~/UNM/android/app): run mobile/build-signalwalk-aar.sh, then mobile/test_shield_bg.py (checks AegisBridge.class and the button in the AAR) and mobile/test_signalwalk.py. Then build Aegis.

20. One app: Aegion everywhere (2026-10-03)

Aegion is the one Aegis app: mobile/main.py (Kivy 2.3.1) on Android, iPhone/iPad, and the Linux, macOS and Windows desktops. Section 15 describes the app itself; this section is the map of the merge. The BUGS.md entries for 3 Oct have the details and test counts.

Names.

Platform layer.

Running it.

What was merged where.

FromInto AegionNotes
Laptop backend answersLaptop tab, "Laptop engine first" (engine/laptop.py, ui/laptop.py)127.0.0.1:8000 on the laptop; over the LAN with the pairing code
Weather / currency / time fast pathsengine/livedata.pylive, never stored; time works offline for built-in cities
~/UNM/signalwalk (Python)mobile/signalwalk/ (sync-signalwalk.sh), engine/walkview.py, ui/signalwalk.pyviewer everywhere; recorder stays the Android AAR
Guardian Security Center scannermobile/guardian/ (sync-guardian.sh), engine/guardian_scan.py, Shield screen cardLinux only, reads only
StockTrack / StockTrack ProMarkets tab (engine/portfolio.py, ui/markets.py)launchers retired, backups in retired-launchers/
SignalDub (~/signal-dub)Choose screen card (engine/studio.py, port 8766)desktop, when installed; FFmpeg missing

LAN sync (laptop and phone).

Android background (Tank 3 Pro findings, 3 Oct).

Building the APK on this network (0.2.0 / 0.2.1 builds, 3 Oct):

After installing 0.2.x on the phone (user actions):

Tests.

Left as they are (not merged):


Session notes

(Append a dated entry here at the end of each work session: what changed, what was verified, what's next.)

2026-09-25 — Handshake page

2026-09-25 — Aegis Mobile standalone APK

2026-09-25 — Updating the second laptop (requirements, knowledge, transfer folder)

2026-09-27 — Desktop integrity and cleanup

2026-10-02 — Health audit fixes (BUGS.md, 2 Oct entries)

2026-10-03 — Curiosity engine and the backend login service (BUGS.md, 3 Oct entry)

2026-10-03 — Shared archive (BUGS.md, 3 Oct entry)

2026-10-03 — One app: Aegion (sections 15 and 20, BUGS.md 3 Oct entries)