-
Notifications
You must be signed in to change notification settings - Fork 0
REPL_ARCHITECTURE
The interactive console is a local UI over the same application services used by the one-shot CLI. The consolidated Issues #46–#49 implementation makes the asynchronous prompt-toolkit/Rich REPL, installed by the main package, the only supported no-argument interactive interface while preserving the one-shot interface.
Status: Implemented for the prompt-toolkit/Rich REPL, context-aware completion, multiline input, bounded background jobs, live progress, and cooperative cancellation with cancellation-resistant shutdown.
The application uses transport-neutral command specifications and
invocation/result contracts between input adapters and application services.
ancestry MODULE ACTION ... remains the one-shot compatibility authority. A
no-argument ancestry invocation starts the asynchronous prompt-toolkit/Rich
REPL. No API, WebUI, multi-user server, autonomous agent, Python execution, or
LLM tool-execution capability is part of this decision.
flowchart LR
Input["prompt_toolkit input\ncommands, completion, multiline, history"]
Router["Session router\nmodule context, safe options"]
Executor["Command executors\ntyped invocation and results"]
Jobs["Bounded job manager\nstate, results, resource locks"]
Services["Application services\npolicy and use cases"]
Presentation["Presentation adapters\nRich, text, JSON"]
Input --> Router --> Executor --> Services
Executor --> Jobs --> Services
Executor --> Presentation
- Input owns terminal reads, asynchronous prompts, multiline editing, Tab completion, history, and EOF. It never interprets shell syntax or accesses databases, keyrings, providers, or networks.
- Session routing owns root versus active-module state and non-secret saved options. It routes parsed invocations and never renders terminal text.
-
Command execution validates typed arguments and calls application
services. It returns serializable DTOs, progress events, or stable
AncestryErrorinstances. -
Application services own use cases and enforce consent, endpoint
policy, immutable source handling, and provider
noneoffline behavior. They do not import UI libraries. - Background jobs run long operations in bounded worker threads, expose serializable lifecycle snapshots and validated progress events, notify presentation subscribers outside execution locks, and serialize mutations by target resource. A context-local cancellation token provides checkpoints, interruptible waits, listener notifications, and named protected sections.
- Presentation maps structured job progress to Rich Live spinners or determinate bars and renders DTOs and coded errors. prompt-toolkit stdout patching coordinates asynchronous output with the active prompt. Rich objects stay in this layer; JSON is a serialization of the same contracts.
The dependency direction is one-way: input -> routing -> execution -> services. Presentation consumes execution results and is not a service
dependency.
- One-shot
ancestry MODULE ACTION ...usage and its parser, typed arguments, JSON output, stable error codes, serializable result shapes, and documented exit codes remain unchanged. - The default no-argument REPL provides root controls (
modules,use,exit/quit) and active-module controls (info,show,set,unset,run,back). - Parsing supports strict quoting, escaped spaces, typed values, repeated
flags, and
NAME=VALUEforms. Shell/Python execution, scripts, aliases, macros, command substitution or expansion, pipes, redirection, and generated executable input are rejected. - Tab completion is derived from command specifications and a frozen session snapshot. It offers commands, actions, unused flags, static enum values, enabled modules, configured profile/consent names, and static secret-reference types.
- Completion never offers secret values, keyring contents, people, trees, prompts, or workspaces. Prompt names are intentionally suppressed because they may contain sensitive data, despite being mentioned in the completion issue description.
- File completion applies only to file-valued arguments and is limited to the current working directory and descendants. It excludes hidden entries and symlinks, rejects traversal and outside absolute paths, and bounds the result count.
- Completion is read-only and must not call databases, keyrings, provider adapters, or networks. It uses command metadata, safe static/session snapshot data, and permitted local directory listings only.
- Secret entry is no-echo, secrets and secret-like commands are excluded from history, and interactive history is stored with owner-only permissions.
- Provider selection and consent stay explicit.
provider=noneremains network-free even when keys or provider SDKs are installed. - The shared services keep RootsMagic inputs immutable and GEDCOM processing rooted, loss-minimal, and atomically published; the REPL cannot weaken these policies through session state.
- Background jobs expose queued, running, completed, failed, and cancelled
states. Their serialized snapshots expose
cancellation_requested_at,cancellation_pending, andcancellation_deferred_by; the last field is a privacy-safe protected-operation label. -
jobs cancel JOB_IDrequests idempotent cooperative cancellation. Ctrl-C at the prompt targets the most recently submitted active job without exiting the REPL. Acknowledged cancellation uses the stableJOB_CANCELLEDcode. -
exitandquitrequirewait,cancel, orstaywhile jobs are active. Invalid decisions useREPL_EXIT_DECISION_REQUIRED; EOF fails safe by waiting and never implicitly cancels active jobs. - Running work observes cancellation at bounded resource, ingress, traversal, provider retry/stream, and storage boundaries. Synchronous provider calls that cannot be interrupted remain bounded by their configured timeout and acknowledge cancellation at the next safe boundary.
- Staged publication is one protected transaction. A request before publication aborts; a request during publication stays pending until the complete bundle commits or rolls back. Publication or rollback failures win over cancellation, and no partial destination is exposed.
- Shutdown drains workers, unsubscribes and closes live presentation, closes provider/execution/cache resources, and finally closes database sessions. Each later cleanup is attempted after an earlier failure, then the original failure or outer cancellation is propagated.
| Concern | One-shot CLI | Interactive REPL |
|---|---|---|
| Command metadata and execution | Builds a typed invocation from the shared CommandSpec registry and resolves it through CommandExecutor
|
Uses the same registry, parser metadata, typed invocation, and CommandExecutor
|
| Success | Returns process exit code 0 and renders the service DTO |
Keeps the session open and renders the same DTO; background result snapshots retain the dispatch exit code |
| Application failure | Renders the bracketed AncestryError.code, safe message, optional remediation, and returns AncestryError.exit_code (normally 1) |
Renders the same bracketed code, safe message, remediation, and serializable details, then keeps the session open |
| Usage, input, or local file failure | Preserves argparse presentation where applicable and returns exit code 2
|
Renders a safe coded usage/input error carrying exit code 2, without a traceback, and keeps the session open |
| JSON |
--json serializes the plain service result without terminal objects |
A command-level --json serializes the same plain service result without Rich objects |
The REPL deliberately has no per-command process exit status because a failed command does not end the process. The numeric exit code remains part of the stable error contract and background dispatch result; automation that needs a process status continues to use the one-shot CLI.
| Area | Status | Boundary |
|---|---|---|
| Shared command specifications and typed invocation contracts | Implemented | One-shot and REPL use the same command metadata |
| Session routing and root/active-module controls | Implemented | State is non-secret and UI-independent |
| Asynchronous prompt-toolkit/Rich REPL | Implemented | Starts with no arguments and is installed by the main package |
| Context-aware completion | Implemented | Static/snapshot-driven, privacy-filtered, CWD-bounded |
| Secure history and no-echo secret entry | Implemented | Owner-only history; secrets excluded and redacted |
| Bounded background jobs | Implemented | Serializable states/results; per-resource mutation serialization |
| Rich Live job progress | Implemented | Spinner or determinate units; stdout-patched prompt coordination |
| Cooperative cancellation | Implemented | Foreground/job controls, serialized state, safe-boundary checks, atomic publication, and ordered shutdown |
ancestry MODULE ACTION ... -> shared parser and CommandExecutor
ancestry -> asynchronous prompt-toolkit/Rich REPL
The REPL and one-shot CLI are sibling adapters, not separate application service paths. All supported adapters must preserve one-shot semantics, provider policy, stable errors, and source-file safety guarantees.
Both adapters now translate parser state through ancestryllm.terminal into
the same transport-neutral CommandInvocation and resolve it through the same
immutable CommandExecutor registry. The REPL does not import the CLI, and the
CLI does not import REPL parser, presentation, or shell modules.
Built-in commands are declared once in the explicit module registry. Each
module has a ModuleDescriptor for identity and implementation location plus a
transport-neutral CommandSpec containing its actions and typed arguments. The
one-shot CLI parser, REPL router, help output, active-module run command, and
completion all consume that metadata.
Module implementations stay thin: they receive parsed, typed invocation data, delegate to application services, and return serializable DTOs or stable coded errors. They do not own terminal input, Rich rendering, storage, provider selection, consent policy, or secret retrieval.
- Calling application services directly from completion or input widgets.
- Reading databases, keyrings, provider state, or network resources while computing completions.
- Returning Rich renderables from services or making JSON depend on terminal formatting.
- Treating an installed SDK or environment key as provider authorization.
- Using shell-like parsing, aliases, redirection, expansion, generated code, or executable commands to make the REPL convenient.
- Suggesting genealogy records, prompt names, workspace names, secret values, or keyring contents from completion.
- Replacing encrypted workspace, GEDCOM atomic publication, or consent checks with in-memory UI state.
prompt-toolkit is a main-package dependency and supplies the asynchronous
prompt, completion primitives, history support, and terminal editing. Rich is
used only by presentation adapters for terminal rendering. The project-specific
completion adapter composes prompt-toolkit public primitives with the existing
command specifications and privacy policy; it does not introduce a second
completion library or a new runtime framework dependency.
The one-shot CLI and REPL are sibling adapters over the same execution and
service contracts. Any implementation that makes services depend on
prompt_toolkit or Rich remains outside the target architecture.
- Home
- CLI reference
- Interactive console guide
- Architecture ownership and dependency contracts
- Bounded file ingress
- Versioning and compatibility
- Continuous integration
- Release runbook
- Encrypted backup and recovery
- First-run storage diagnostics
- GEDCOM compatibility and release checks
- Built-in module authoring
- Privacy and consent
- Provider guide
- Local LLM benchmarks
- Local-first retrieval evaluation
- Wiki synchronization
- Wiki operations and recovery
- Security response checklist
- Electron and FastAPI desktop ADR
- Data-flow threat model and control matrix