Status: design analysis (2026-08)
Scope: what should be redesigned given modern agentic products and LangGraph, and what is non-core enough to remove or deprecate.
Constraint: public surface stays small (init, assistant, interactive, config, status). No long-lived import shims.
Related: ARCHITECTURE.md, AI_ARCHITECTURE.md, TECHNICAL_DEBT.md.
OpenFatture is local-first Italian electronic invoicing with an optional agentic assistant. The model does not own business rules: FatturaPA, SDI, validation, and mutations stay deterministic.
| Layer | Responsibility |
|---|---|
| Domain core | Billing, SDI, payment, PDF, storage, events, hooks |
| Assistant runtime | One multi-turn agent that calls domain tools |
| Optional satellites | RAG, forecasting, Lightning, scraper, voice — only if product-proven |
Today the tree mixes those layers and runs two incomplete AI runtimes in parallel.
What exists
| Runtime | Location | Used by product? |
|---|---|---|
| A. Chat + tools | ChatAgent → NativeToolOrchestrator / ReActOrchestrator → ToolRegistry |
Yes — openfatture assistant |
| B. LangGraph workflows | orchestration/workflows/* (InvoiceCreationWorkflow, ComplianceCheckWorkflow, CashFlowAnalysisWorkflow) |
No — tests and internal wiring only |
C. Specialized BaseAgents |
invoice_assistant, tax_advisor, compliance, payment insight, orphan analytics agents |
Partly — only inside LangGraph (B) or payment insight service |
Why it’s wrong now
Modern agentic products converge on one graph-shaped runtime:
We have reinvented tool loops (A) and adopted LangGraph (B) without connecting them to the CLI. LangGraph is paid for as a dependency and maintained in tests, but the user-facing path never enters a StateGraph.
Target
CLI assistant / interactive
│
▼
┌───────────────────────────────┐
│ LangGraph assistant graph │ ← single runtime
│ - model node │
│ - tool node(s) │
│ - optional subgraphs │ (invoice draft, compliance)
│ - interrupt on write tools │
│ - checkpointer (session) │
└───────────────────────────────┘
│
▼
domain application services (billing, sdi, payment, …)
ReActOrchestrator once providers with native tools cover the matrix (OpenAI, Anthropic, current Ollama all support tools; keep a thin fallback only if measured).NativeToolOrchestrator into LangGraph ToolNode / prebuilt agent patterns.ai/session is largely disconnected from the CLI chat loop, which keeps a raw list[dict] in memory).What exists
Many “agents” are really prompt + structured output wrappers:
InvoiceAssistantAgent, TaxAdvisorAgent, PaymentInsightAgentClientIntelligenceAgent, InvoiceAnalysisAgent, PerformanceAnalyticsAgentPlus a full custom hierarchy: AgentProtocol / BaseAgent / per-agent *Context types (~context.py bloat).
Why it’s wrong now
2024–2026 product pattern:
Target
expand_invoice_description (or subgraph step)suggest_vat_treatmentWhat exists
Tool / ToolParameter OpenAI-shaped modelsToolRegistry (~700+ lines) with circuit breaker, bulkhead, rate limit, confirmationWhy it’s wrong now
Target
@tool-like registration).execute → application service only; ban new raw session access in tools.What exists
Custom BaseLLMProvider + OpenAI / Anthropic / Ollama implementations (~2.4k LOC): streaming, tool formats, token accounting, errors — duplicated per vendor.
Why it’s wrong now
SDKs and LangGraph model wrappers already cover streaming and tools. Maintaining three full adapters is high cost for a CLI product.
Target (pick one, prefer thin)
openai / anthropic / Ollama HTTP) returning a minimal internal ModelResponse, orKeep: config selection, cost estimate hooks, redaction. Drop: parallel streaming event systems if the graph already streams.
What exists
| Concern | Implementation | Wired to CLI assistant? |
|---|---|---|
| Multi-turn chat | In-memory list[dict] in assistant.py |
Yes |
| File session store | ai/session |
Largely no |
| LangGraph checkpoint | Optional in workflows | Only workflows |
| HITL workflows | human_loop.py + state reviews |
Workflows only |
| Tool confirmation | requires_confirmation on tools |
Registry path |
Docs claim sessions go through get_session_store; the public assistant does not use it.
Target
human_loop into that gate; stop maintaining two approval UX paths.What exists
ChromaDB, embeddings (OpenAI + sentence-transformers), auto-update queue with stubs, knowledge tools — ~3.5k LOC + heavy deps.
Why rethink
For freelancers, RAG over regulations is nice-to-have, not the core job (“issue and send a valid invoice”). Operational cost (models, index drift, stubs) is high.
Target
knowledge.search when quality is measured.What exists
Prophet + XGBoost ensemble, retraining scheduler, cash_flow_predictor agent, LangGraph cash_flow workflow — ~4.5k+ LOC, heavy native deps.
Why rethink
This is a data-science product, not required for FatturaPA. It pulls the install and CI matrix (libomp, etc.) and is not on the public CLI.
Target
ml extra or separate package later.What exists
payment / lightning: DDD folderscore: flat entity bags + empty packagesutils: grab-bagservices.pdf: third naming schemeTarget (unchanged from modernization plan)
billing/ sdi/ payment/ pdf/
events/ hooks/ storage/ platform/
ai/ # assistant runtime + tools only
Import rule: ai → application services → domain/storage, never tools → ORM as the long-term pattern.
| Area | Reality | Redesign stance |
|---|---|---|
| plugins | Discovery/registry incomplete | Removed; hooks + tools until MCP |
| voice | ~1.7k LOC, no public CLI command | Deprecate or archive until demand |
| web_scraper | Playwright stack, config hooks, not product path | Removed (D0) |
| lightning | DDD + gRPC stubs; lifespan integration | Keep as hard optional; do not block core; finish LND or remove client pretence |
| media/ | Dashboards, tapes, OBS presets | Not runtime product; keep as ops/marketing only, never import from package |
| landing-page/ | Separate static site | Keep out of Python package |
┌──────────── public CLI ────────────┐
│ init config status │
│ assistant / interactive ──┐ │
└───────────────────────────│────────┘
▼
┌────────────────────────────────┐
│ AssistantGraph (LangGraph) │
│ model ↔ tools ↔ interrupts │
│ checkpointer = session │
└────────────┬───────────────────┘
│ tools only
┌──────────────────────┼──────────────────────┐
▼ ▼ ▼
billing app sdi app payment app
│ │ │
└──────────────────────┼──────────────────────┘
▼
storage + events + hooks
Naming
| Avoid | Prefer |
|---|---|
core |
billing (+ events / hooks) |
utils |
platform |
services.pdf |
pdf |
web_scraper |
remove or scraper satellite |
*Agent for pure prompts |
tools / skills / graph nodes |
| Dual “orchestrator” types | one graph runtime |
Prioritized for deletion or archival under docs/history/ + git history (no shims).
client_intelligence_agent, invoice_analysis_agent, performance_analytics_agent + matching contexts/output models if unused.openfatture/ai/voice) until a real CLI story exists.ai/session to interactive or delete unused store code paths.| Module | Action |
|---|---|
ai/ml + cash flow predictor |
optional extra only; freeze features |
ai/rag + auto_update stubs |
optional; implement or delete stubs |
lightning |
optional; real gRPC or honest “experimental” status |
ai/feedback |
keep minimal metrics; drop productized feedback UI ambitions |
ai/cache |
keep only if measured cost win; else simplify |
| Phase | Work | Outcome |
|---|---|---|
| D0 | Cut orphans: agents, voice, scraper from default tree; freeze ML/RAG extras | Done |
| D1 | Domain rename (billing, events, hooks, platform, pdf) |
Done |
| D2 | Tools → application services only; slim registry | Done |
| D3 | Single assistant runtime entry; LangGraph helper | Done (product path); multi-node graph TBD |
| D4 | Absorb invoice/tax/compliance as subgraph or tools; delete parallel workflow product | One UX |
| D5 | Thin providers; delete ReAct if unused | Less framework |
| D6 | Optional RAG/ML only with measured quality gates | Honest extras |
D0–D1 landed in the 2.0 modernization tree; D2–D5 are the remaining AI-era redesign.
fattura, cliente, …)When touching AI code, ask:
*Agent class?If the answer is “extend the zoo”, stop and redesign.