- Python 99.1%
- Makefile 0.9%
| .vscode | ||
| configs | ||
| demo | ||
| docs | ||
| examples | ||
| external | ||
| local_models | ||
| src | ||
| test_documents | ||
| tests | ||
| .gitignore | ||
| .markdownlint.yml | ||
| environment.lock.yml | ||
| environment.yml | ||
| Makefile | ||
| pyproject.toml | ||
| pyrightconfig.json | ||
| README.md | ||
Administration Copilot
Administration Copilot is a local-first Python workspace for building modular AI-assisted administrative workflows. The long-term system is meant to ingest incoming work items such as e-mails, PDFs, scans, uploads, or API payloads, classify and route them, extract structured business data where needed, retrieve missing context, and create review-only outputs for human approval.
The project is intentionally split into small modules instead of one large assistant package. The current implemented MVP focuses on three review-only workflows: e-mail reply drafting, action-only task extraction, and offer/quote extraction from PDFs or scans. It also includes a standalone RAG retrieval module for local context lookup experiments. The workflow modules use shared model/tool infrastructure, SQLModel-based inbox persistence, LangGraph checkpointing, and a synthetic test-document corpus.
The official local MVP entry point is now admin-flow: a headless orchestration
CLI that runs one source file through ingestion, normalization, routing,
optional reviewed route fallback, explicit/safe acceptance, downstream
execution, persistence, and a chronological result payload.
Current State
Implemented today:
admin_mail: LangGraph-orchestrated e-mail reply drafting with native tool-calling, optional RAG-backed context retrieval, deterministic review guards, and SQLite checkpoints.admin_tasks: LangGraph-orchestrated extraction of review-only tasks from already routed e-mails that should not receive a direct reply.admin_inbox: SQLModel persistence for incoming items, their body, document, and attachment parts, e-mails, review-only drafts/tasks, and lightweight normalization of stored.eml/text files.admin_common: shared tool contracts, OpenAI-compatible adapters, local llama.cpp client, and LangGraph SQLite checkpointing.admin_connectors: source connectors, currently a local hot-folder connector that ingests stable files intoadmin_inbox.admin_route: deterministic first-hop routing for normalized incoming items into mail reply, task extraction, document processing, human review, or no action, with persisted reviewable route decisions and optional reviewed LLM fallback for otherwise uncertain text items.admin_flow: official headless MVP orchestration across connector, inbox, routing, optional fallback, accepted route execution, and result summary.admin_eval: offline evaluation helpers, currently focused on measuring deterministic routing against the synthetic fixture metadata.admin_idp: LangGraph-orchestrated offer/quote extraction from PDFs or images, usingpymupdf4llmfor PDF text and EasyOCR as CPU-only OCR fallback.admin_rag: standalone Chroma/E5 retrieval over synthetic context fixtures, with opt-in context-provider integration for mail and task workflows.test_documents: neutral synthetic.emland PDF fixtures with separate metadata labels for future routing, IDP, RAG, and mail tests.
Prepared but not implemented yet:
- GraphRAG, reranking, and RAG-backed context for document extraction.
- Real mailbox/API connectors, mailbox sync, sending e-mail, and human review UI.
- A standalone Streamlit portfolio demo lives under
demo/. It visualizes the current PDF/IDP flow, but it is not a production review UI.
All generated e-mail replies are drafts only. No module sends e-mail.
Module Layout
src/
|-- admin_common/ # shared contracts, adapters, orchestration, model clients
|-- admin_connectors/ # local source connectors such as hot-folder ingestion
|-- admin_inbox/ # incoming-item boundary; e-mail, draft, and task persistence
|-- admin_idp/ # review-only document processing and quote extraction
|-- admin_mail/ # review-only e-mail reply drafting
|-- admin_rag/ # standalone Chroma/E5 retrieval and optional context source
|-- admin_tasks/ # review-only action/task extraction from e-mails
|-- admin_route/ # deterministic first-hop routing for normalized items
|-- admin_flow/ # official headless MVP orchestration over the modules
`-- admin_eval/ # offline quality checks over fixture metadata
Future GraphRAG, reranking, and document-processing RAG are described in docs but are not implemented yet.
The package names follow the module boundaries: admin-mail for reply drafts
and admin-tasks for action-only task extraction. The repository-level product
vision is broader: Administration Copilot.
Environment
Create the Conda environment:
conda env create -f environment.yml
/home/archuser/miniconda3/envs/admin-ai/bin/python -m pip install -e ".[dev,rag]"
If admin-ai already exists:
conda env update -n admin-ai -f environment.yml --prune
/home/archuser/miniconda3/envs/admin-ai/bin/python -m pip install -e ".[dev,rag]"
The local admin-ai environment installs EasyOCR with CPU-only PyTorch wheels
for OCR fallback. If you install outside Conda and want OCR support, use the
ocr extra with a CPU-only PyTorch setup.
The Makefile and VSCode workspace default to the admin-ai Python executable
directly. Activating the Conda environment is still convenient for interactive
shell work, but it is not required for make targets.
Checks
make ci
make markdownlint
This runs Ruff, Mypy, focused Pyright checks, and Pytest over the current
first-party code, demo code, examples, and test corpus helpers. The Makefile uses the
project's admin-ai Python by default; portable users can override it with
PYTHON=/path/to/python make ci. make markdownlint checks the repository
documentation with the shared Markdownlint configuration.
Local Runtime
Local runtime artifacts are grouped under one ignored directory:
local_runtime/
|-- inbox.sqlite
|-- langgraph_checkpoints.sqlite
|-- flow_checkpoints.sqlite
|-- demo/
|-- flow_runs/
|-- idp_parts/
|-- rag/
|-- incoming/
|-- processing/
|-- processed/
`-- failed/
inbox.sqlite stores business state from admin_inbox.
langgraph_checkpoints.sqlite stores technical LangGraph run state.
flow_checkpoints.sqlite stores technical state for the outer admin-flow
orchestration graph.
demo/ stores disposable Streamlit portfolio-demo runtime state.
flow_runs/ stores isolated per-run hot-folder folders created by admin-flow.
idp_parts/ stores extracted document attachments from .eml files when a
routed e-mail needs document processing.
rag/chroma/ stores disposable local Chroma indexes for admin_rag.
incoming/ stores local source files used by connectors.
The connector layer stores raw source files first. admin_inbox can then
normalize stored .eml and plain-text items into a small structured shape for
future routing. A normalized item can contain parts: for example an e-mail body
plus PDF attachments. PDFs and images can now be routed to admin_idp for
review-only offer/quote extraction.
The low-level route dispatcher connects the pieces without executing downstream workflows automatically:
StoredIncomingItem
-> normalize_incoming_item(...)
-> route_normalized_item(...)
-> StoredRouteDecision
-> incoming item marked routed
-> explicit accept/override
-> explicit execute for mail/task/document routes
Route decisions are reviewable business records. A mail_reply,
task_extraction, or document_processing route starts the LLM workflow only
after the decision is accepted or overridden and then executed explicitly
through admin-route execute. human_review and no_action remain parked.
For the MVP, prefer the higher-level admin-flow run command. It performs the
same steps as one reproducible run and can optionally auto-accept safe,
non-safety routes for local demos and smoke tests.
Hot-Folder Connector
Create an empty local hot-folder layout:
admin-connectors hot-folder init
This creates:
local_runtime/
|-- incoming/
|-- processing/
|-- processed/
`-- failed/
local_runtime/ is ignored by Git. Put test files directly into
local_runtime/incoming/, then scan once into local_runtime/inbox.sqlite:
admin-connectors hot-folder scan --stable-after-s 0
Limit ingestion to selected extensions when needed:
admin-connectors hot-folder scan --allow-extension .eml --allow-extension .pdf
The connector detects duplicate files by SHA-256. Duplicates are archived under
processed/ but are not stored as new inbox items. The inbox database enforces
that digest as unique for incoming items. If ingestion fails after a file has
already moved through processing/, the latest known file path is moved to
failed/ instead of leaving a stranded file behind.
For a simple polling watcher while the program is running:
admin-connectors hot-folder watch --interval-s 5
Documentation
- API Reference: current public Python APIs, CLI, tool calling, persistence, and orchestration boundaries.
- Architecture: current module boundaries and runtime layers.
- Walkthrough: guided end-to-end handbook for the current workflows.
- Test Document Corpus: synthetic fixture scope and generation notes.
- Streamlit Portfolio Demo: screenshot-friendly live PDF/IDP demo.
CLI And Examples
The installed CLIs expose connector, routing, reply, and task workflows:
admin-mail --help
admin-mail reply-draft --help
admin-mail tool-contracts
admin-tasks --help
admin-tasks extract --help
admin-idp --help
admin-idp extract --help
admin-rag --help
admin-rag index --help
admin-rag query --help
admin-connectors --help
admin-connectors hot-folder --help
admin-route --help
admin-flow --help
admin-flow run --help
admin-eval --help
admin-eval routing --help
Official headless MVP sequence:
admin-rag index test_documents/rag_seed --reset --json
admin-flow run test_documents/documents/item_000019.eml \
--language de \
--use-rag-context \
--use-llm-route-fallback \
--auto-accept safe \
--json
This command ingests the source file through an isolated local hot-folder run,
stores it in admin_inbox, normalizes it, routes it, optionally uses the
reviewed route fallback only for uncertain text, accepts safe executable routes,
and then executes the accepted mail/task/document workflow.
For repeatable local runs, the same settings can be put into a TOML config and overridden per command:
admin-flow run test_documents/documents/item_000019.eml \
--config configs/admin-flow.local.example.toml \
--auto-accept safe \
--use-rag-context \
--json
Two more example configs are available:
configs/admin-flow.fast-dev.example.toml: faster local smoke settings.configs/admin-flow.full-local.example.toml: fuller local run with RAG and reviewed route fallback enabled.
admin-flow returns structured failure payloads with the failed node, code,
message, error type, and details. The llama.cpp client also supports retrying
transient HTTP failures for real HTTP calls; fake transports used in tests still
fail immediately.
The main execution levels are:
| Level | Use | Notes |
|---|---|---|
admin-flow |
Official local MVP entry point | Ingests, routes, accepts safely, executes, and persists. |
admin-route |
Manual route debugging | Lets you route, accept, override, and execute step by step. |
admin-mail, admin-tasks, admin-idp |
Focused module runs | Useful when one module should be tested directly. |
admin-rag |
Standalone retrieval | Index and query context data independently. |
| Internal workflow helpers | Tests/debugging | Kept for fake transports and narrow unit tests. |
Review-capable JSON payloads include a compact review_summary so failed
review guards can be spotted without reading the raw tool-message payload.
Offline routing evaluation is available without starting llama.cpp:
admin-eval routing --json
This compares deterministic routing against test_documents/metadata and
prints aggregate accuracy plus mismatches. Treat this as a quality signal, not
as a guarantee that the router is finished.
Low-level routing sequence for debugging or manual stepping:
admin-connectors hot-folder scan --stable-after-s 0 --json
admin-route route <incoming_item_id> --json
admin-route accept <decision_id> --json
admin-route execute <decision_id> \
--language de \
--context-note "Use trusted local context for this review-only draft." \
--json
Examples:
python examples/run_email_reply_workflow.py --show-raw-tool-arguments
python examples/run_email_tasks_workflow.py --show-raw-tool-arguments
python examples/run_tool_contracts.py
These scripts are still useful for learning and inspecting native tool calls in
one module at a time. They are not the official source-to-result MVP path; use
admin-flow run for that.
Run a direct document extraction smoke against a local llama.cpp server:
admin-idp extract test_documents/documents/item_000028.pdf \
--document-type quote \
--language de \
--json
Build and query the standalone RAG seed index:
admin-rag index test_documents/rag_seed \
--db-dir local_runtime/rag/chroma \
--reset \
--json
admin-rag query "Montagefenster Nordtor Bauleiter" \
--db-dir local_runtime/rag/chroma \
--top-k 5 \
--json
Use the same index as trusted context for an accepted mail or task route:
admin-route execute <decision_id> \
--language de \
--use-rag-context \
--rag-db-dir local_runtime/rag/chroma \
--json
Routing remains deterministic by default. The optional LLM route fallback is
available only for uncertain, non-safety text items and is reviewed by a local
tool before it can create a replacement decision. RAG is used only after a route
decision has been accepted and only as the get_context provider for mail
replies or task extraction.
The e-mail bodies and local example context used by the workflow examples live
together under examples/data/:
reply_request_de.txt
reply_context_de.txt
task_request_de.txt
task_context_de.txt
The real local smoke path is llama.cpp + native tool-calling + LangGraph +
SQLite checkpointing. By default, make serve uses the local Qwen3 dev model:
make serve
admin-flow run test_documents/documents/item_000019.eml \
--use-rag-context \
--use-llm-route-fallback \
--auto-accept safe \
--json
python examples/run_email_reply_workflow.py --show-raw-tool-arguments
python examples/run_email_tasks_workflow.py --show-raw-tool-arguments
admin-idp extract test_documents/documents/item_000028.pdf --document-type quote --json
MODEL_PATH is still overrideable for model comparisons:
make serve MODEL_PATH=local_models/Qwen3-4B-Instruct-2507-Q5_K_M.gguf
make serve MODEL_PATH=local_models/Meta-Llama-3.1-8B-Instruct-Q8_0.gguf
make serve MODEL_PATH=local_models/LFM2.5-8B-A1B-Q8_0.gguf
Test Document Corpus
Curated synthetic fixtures live under:
test_documents/
|-- documents/ # neutral source files such as item_000001.eml
|-- metadata/ # labels, expected routes, thread links, safety flags
`-- rag_seed/ # retrieval context for standalone admin_rag tests
Source filenames and attachment names are intentionally neutral to avoid data leakage. Semantic labels belong in metadata only. The corpus is curated in place; do not regenerate it from a script.