finizi-app 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. finizi_app-0.1.0/.dockerignore +14 -0
  2. finizi_app-0.1.0/.gitignore +111 -0
  3. finizi_app-0.1.0/CHANGELOG.md +26 -0
  4. finizi_app-0.1.0/LICENSE +9 -0
  5. finizi_app-0.1.0/PKG-INFO +254 -0
  6. finizi_app-0.1.0/README.md +207 -0
  7. finizi_app-0.1.0/docs/api-key-auth.md +119 -0
  8. finizi_app-0.1.0/docs/architecture.md +110 -0
  9. finizi_app-0.1.0/docs/cli.md +286 -0
  10. finizi_app-0.1.0/docs/contributing.md +110 -0
  11. finizi_app-0.1.0/docs/glossary.md +156 -0
  12. finizi_app-0.1.0/docs/install.md +310 -0
  13. finizi_app-0.1.0/docs/mcp.md +134 -0
  14. finizi_app-0.1.0/docs/security.md +106 -0
  15. finizi_app-0.1.0/finizi_app/__init__.py +3 -0
  16. finizi_app-0.1.0/finizi_app/cli/__init__.py +12 -0
  17. finizi_app-0.1.0/finizi_app/cli/__main__.py +11 -0
  18. finizi_app-0.1.0/finizi_app/cli/commands/__init__.py +37 -0
  19. finizi_app-0.1.0/finizi_app/cli/commands/_cashbook_impl.py +180 -0
  20. finizi_app-0.1.0/finizi_app/cli/commands/api_keys.py +44 -0
  21. finizi_app-0.1.0/finizi_app/cli/commands/auth.py +200 -0
  22. finizi_app-0.1.0/finizi_app/cli/commands/banks.py +36 -0
  23. finizi_app-0.1.0/finizi_app/cli/commands/bhxh.py +31 -0
  24. finizi_app-0.1.0/finizi_app/cli/commands/cashbooks.py +38 -0
  25. finizi_app-0.1.0/finizi_app/cli/commands/celery.py +31 -0
  26. finizi_app-0.1.0/finizi_app/cli/commands/coa.py +90 -0
  27. finizi_app-0.1.0/finizi_app/cli/commands/company.py +26 -0
  28. finizi_app-0.1.0/finizi_app/cli/commands/doctor.py +25 -0
  29. finizi_app-0.1.0/finizi_app/cli/commands/documents.py +42 -0
  30. finizi_app-0.1.0/finizi_app/cli/commands/einvoice.py +45 -0
  31. finizi_app-0.1.0/finizi_app/cli/commands/entities.py +30 -0
  32. finizi_app-0.1.0/finizi_app/cli/commands/inventory.py +26 -0
  33. finizi_app-0.1.0/finizi_app/cli/commands/invoices.py +122 -0
  34. finizi_app-0.1.0/finizi_app/cli/commands/journal.py +49 -0
  35. finizi_app-0.1.0/finizi_app/cli/commands/ledger.py +31 -0
  36. finizi_app-0.1.0/finizi_app/cli/commands/memory.py +28 -0
  37. finizi_app-0.1.0/finizi_app/cli/commands/payments.py +494 -0
  38. finizi_app-0.1.0/finizi_app/cli/commands/payroll.py +50 -0
  39. finizi_app-0.1.0/finizi_app/cli/commands/products.py +56 -0
  40. finizi_app-0.1.0/finizi_app/cli/commands/purchase_orders.py +652 -0
  41. finizi_app-0.1.0/finizi_app/cli/commands/reports.py +30 -0
  42. finizi_app-0.1.0/finizi_app/cli/commands/sale_orders.py +249 -0
  43. finizi_app-0.1.0/finizi_app/cli/commands/tax.py +31 -0
  44. finizi_app-0.1.0/finizi_app/cli/commands/vendors.py +65 -0
  45. finizi_app-0.1.0/finizi_app/cli/main.py +234 -0
  46. finizi_app-0.1.0/finizi_app/core/__init__.py +19 -0
  47. finizi_app-0.1.0/finizi_app/core/apikeystore.py +40 -0
  48. finizi_app-0.1.0/finizi_app/core/clients.py +414 -0
  49. finizi_app-0.1.0/finizi_app/core/credentials.py +347 -0
  50. finizi_app-0.1.0/finizi_app/core/errors.py +108 -0
  51. finizi_app-0.1.0/finizi_app/core/filters.py +37 -0
  52. finizi_app-0.1.0/finizi_app/core/models.py +50 -0
  53. finizi_app-0.1.0/finizi_app/core/workflows/__init__.py +92 -0
  54. finizi_app-0.1.0/finizi_app/core/workflows/ai_classify_journal.py +59 -0
  55. finizi_app-0.1.0/finizi_app/core/workflows/auth_login.py +179 -0
  56. finizi_app-0.1.0/finizi_app/core/workflows/auth_logout.py +50 -0
  57. finizi_app-0.1.0/finizi_app/core/workflows/bank_transactions.py +146 -0
  58. finizi_app-0.1.0/finizi_app/core/workflows/bulk_dispatch.py +47 -0
  59. finizi_app-0.1.0/finizi_app/core/workflows/calculate_payroll.py +54 -0
  60. finizi_app-0.1.0/finizi_app/core/workflows/cancel_einvoice.py +33 -0
  61. finizi_app-0.1.0/finizi_app/core/workflows/cash_bank_payments.py +594 -0
  62. finizi_app-0.1.0/finizi_app/core/workflows/check_tax_status.py +76 -0
  63. finizi_app-0.1.0/finizi_app/core/workflows/create_product.py +76 -0
  64. finizi_app-0.1.0/finizi_app/core/workflows/dispatch_job.py +62 -0
  65. finizi_app-0.1.0/finizi_app/core/workflows/generate_tax_report.py +46 -0
  66. finizi_app-0.1.0/finizi_app/core/workflows/get_coa.py +236 -0
  67. finizi_app-0.1.0/finizi_app/core/workflows/get_company.py +73 -0
  68. finizi_app-0.1.0/finizi_app/core/workflows/get_inventory_receipt.py +54 -0
  69. finizi_app-0.1.0/finizi_app/core/workflows/get_invoice.py +39 -0
  70. finizi_app-0.1.0/finizi_app/core/workflows/get_ledger_entries.py +112 -0
  71. finizi_app-0.1.0/finizi_app/core/workflows/get_vendor.py +52 -0
  72. finizi_app-0.1.0/finizi_app/core/workflows/health_check.py +55 -0
  73. finizi_app-0.1.0/finizi_app/core/workflows/import_invoice_pdf.py +50 -0
  74. finizi_app-0.1.0/finizi_app/core/workflows/import_invoice_xml.py +48 -0
  75. finizi_app-0.1.0/finizi_app/core/workflows/issue_einvoice.py +56 -0
  76. finizi_app-0.1.0/finizi_app/core/workflows/list_documents.py +92 -0
  77. finizi_app-0.1.0/finizi_app/core/workflows/list_entities.py +30 -0
  78. finizi_app-0.1.0/finizi_app/core/workflows/list_invoices.py +75 -0
  79. finizi_app-0.1.0/finizi_app/core/workflows/list_payrolls.py +92 -0
  80. finizi_app-0.1.0/finizi_app/core/workflows/manage_api_keys.py +55 -0
  81. finizi_app-0.1.0/finizi_app/core/workflows/manage_vendor.py +97 -0
  82. finizi_app-0.1.0/finizi_app/core/workflows/match_products.py +75 -0
  83. finizi_app-0.1.0/finizi_app/core/workflows/parse_bank_statement.py +50 -0
  84. finizi_app-0.1.0/finizi_app/core/workflows/pay_invoice.py +57 -0
  85. finizi_app-0.1.0/finizi_app/core/workflows/purchase_orders.py +497 -0
  86. finizi_app-0.1.0/finizi_app/core/workflows/reverse_journal.py +96 -0
  87. finizi_app-0.1.0/finizi_app/core/workflows/sale_orders.py +213 -0
  88. finizi_app-0.1.0/finizi_app/core/workflows/search_memory.py +55 -0
  89. finizi_app-0.1.0/finizi_app/core/workflows/search_vendor.py +41 -0
  90. finizi_app-0.1.0/finizi_app/core/workflows/switch_entity.py +38 -0
  91. finizi_app-0.1.0/finizi_app/core/workflows/sync_bhxh.py +88 -0
  92. finizi_app-0.1.0/finizi_app/core/workflows/workflow_errors.py +20 -0
  93. finizi_app-0.1.0/finizi_app/mcp/__init__.py +13 -0
  94. finizi_app-0.1.0/finizi_app/mcp/__main__.py +6 -0
  95. finizi_app-0.1.0/finizi_app/mcp/server.py +276 -0
  96. finizi_app-0.1.0/finizi_app/mcp/transports/__init__.py +1 -0
  97. finizi_app-0.1.0/finizi_app/mcp/transports/http.py +85 -0
  98. finizi_app-0.1.0/pyproject.toml +109 -0
  99. finizi_app-0.1.0/tests/__init__.py +0 -0
  100. finizi_app-0.1.0/tests/conftest.py +61 -0
  101. finizi_app-0.1.0/tests/e2e/__init__.py +0 -0
  102. finizi_app-0.1.0/tests/integration/__init__.py +0 -0
  103. finizi_app-0.1.0/tests/integration/test_cli_smoke.py +1078 -0
  104. finizi_app-0.1.0/tests/integration/test_mcp_server.py +147 -0
  105. finizi_app-0.1.0/tests/unit/__init__.py +0 -0
  106. finizi_app-0.1.0/tests/unit/test_apikeystore.py +48 -0
  107. finizi_app-0.1.0/tests/unit/test_auth_status.py +89 -0
  108. finizi_app-0.1.0/tests/unit/test_clients.py +115 -0
  109. finizi_app-0.1.0/tests/unit/test_credentials.py +246 -0
  110. finizi_app-0.1.0/tests/unit/test_mcp_server.py +81 -0
  111. finizi_app-0.1.0/tests/unit/test_workflows.py +2615 -0
  112. finizi_app-0.1.0/uv.lock +1517 -0
@@ -0,0 +1,14 @@
1
+ __pycache__/
2
+ *.pyc
3
+ *.pyo
4
+ .pytest_cache/
5
+ .mypy_cache/
6
+ .ruff_cache/
7
+ .coverage
8
+ htmlcov/
9
+ build/
10
+ *.egg-info/
11
+ .venv/
12
+ venv/
13
+ tests/
14
+ output/
@@ -0,0 +1,111 @@
1
+ # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2
+
3
+ # dependencies
4
+ /node_modules
5
+ /.pnp
6
+ .pnp.*
7
+ .yarn/*
8
+ !.yarn/patches
9
+ !.yarn/plugins
10
+ !.yarn/releases
11
+ !.yarn/versions
12
+
13
+ # testing
14
+ /coverage
15
+
16
+ # next.js
17
+ /.next/
18
+ /out/
19
+ dist/
20
+ bin/
21
+
22
+ # production
23
+ /build
24
+
25
+ # misc
26
+ .DS_Store
27
+ *.pem
28
+
29
+ # debug
30
+ npm-debug.log*
31
+ yarn-debug.log*
32
+ yarn-error.log*
33
+ .pnpm-debug.log*
34
+
35
+ # package manager
36
+ package-lock.json
37
+ yarn.lock
38
+ pnpm-lock.yaml
39
+
40
+ # semantic-release
41
+ .nyc_output
42
+
43
+ # env files (can opt-in for committing if needed)
44
+ .env*
45
+ !.env.example
46
+
47
+ # vercel
48
+ .vercel
49
+
50
+ # typescript
51
+ *.tsbuildinfo
52
+ next-env.d.ts
53
+
54
+ # flutter
55
+ .dart_tool
56
+ build
57
+ GoogleService-Info.plist
58
+
59
+ repomix-output.xml
60
+ .serena/cache
61
+ plans/**/*
62
+ !plans/templates/*
63
+ screenshots/*
64
+ docs/screenshots/*
65
+ logs.txt
66
+ test-ck
67
+ __pycache__
68
+
69
+ # CK meta commands
70
+ prompt.md
71
+ ck.md
72
+
73
+ # Generated runtime layout for release/install smoke tests
74
+ /.claude/
75
+ # But track repo-level rules that Claude Code reads
76
+ !/.claude/rules/
77
+
78
+ # Local-only state inside tracked claude source
79
+ claude/agent-memory/
80
+ claude/hooks/.logs/
81
+ claude/session-state/latest.md
82
+ claude/session-state/archive/
83
+ claude/settings.bak.json
84
+ claude/skills/ai-multimodal/assets/demo-*.claude/session-state/*.tmp
85
+
86
+ # Gemini CLI settings (symlink to staged .claude/.mcp.json)
87
+ .gemini/settings.json
88
+ # Showoff/marketing assets (images, showcases)
89
+ assets/
90
+ # Exception: use-mcp ships a persistent tool catalog at assets/tools.json
91
+ !claude/skills/use-mcp/assets/
92
+ !claude/skills/use-mcp/assets/**
93
+
94
+ # External repos for study/reference
95
+ external/
96
+
97
+ # Git worktrees (local development only)
98
+ worktrees/
99
+
100
+ # Local credential files (never commit) — covers apikeys, secrets.txt, *.pem,
101
+ # and any *.key / *.token that land at the repo root or in dev folders.
102
+ apikeys
103
+ secrets.txt
104
+ *.pem
105
+ *.key
106
+ *.token
107
+
108
+ # Per-package virtualenvs (created when running `python -m venv .venv`
109
+ # inside finizi-app/ or other packages)
110
+ finizi-app/.venv
111
+ **/.venv
@@ -0,0 +1,26 @@
1
+ # Changelog
2
+
3
+ ## Unreleased
4
+
5
+ ### Added
6
+
7
+ - `finizi-app invoices list`: new `--invoice-series TEXT` and
8
+ `--invoice-number INTEGER` filter flags. Use them to look up an
9
+ invoice by its Vietnamese (series, number) tuple (e.g. `C26MAP-842`)
10
+ in O(1) without paginating. Both flags can be set standalone or
11
+ together, and AND-combine with the existing `--status`, `--date-from`,
12
+ `--date-to`, `--query`, and `--vendor-id` filters. The matching
13
+ backend support is pending in the upstream `b4b-api` list endpoint
14
+ (issue #18) — once it lands, `bank-reconciler` and other skills can
15
+ use the new flags directly.
16
+
17
+ ### Breaking changes
18
+
19
+ - `finizi-app payments list`: CLI flags renamed to match the server schema.
20
+ Use `--date-from` / `--date-to` / `--partner-id` (was `--from-date` /
21
+ `--to-date` / `--vendor-id`). The MCP `Params` fields are now
22
+ `date_from` / `date_to` / `partner_id` (was `from_date` / `to_date` /
23
+ `vendor_id`). The old flags are rejected by Typer and the old field
24
+ names by Pydantic — no shim is provided because the previous values
25
+ were silently dropped by the server. Update scripts and MCP callers
26
+ before upgrading.
@@ -0,0 +1,9 @@
1
+ Proprietary License
2
+
3
+ Copyright (c) 2026 Finizi Engineering. All rights reserved.
4
+
5
+ This software is proprietary and confidential. Unauthorized copying,
6
+ distribution, modification, or use of this software, via any medium, is
7
+ strictly prohibited.
8
+
9
+ For licensing inquiries, contact engineering@finizi.app.
@@ -0,0 +1,254 @@
1
+ Metadata-Version: 2.4
2
+ Name: finizi-app
3
+ Version: 0.1.0
4
+ Summary: CLI + MCP server for the Finizi.AI Vietnamese accounting/tax platform
5
+ Project-URL: Homepage, https://github.com/finizi-app/finizi-agentize
6
+ Project-URL: Repository, https://github.com/finizi-app/finizi-agentize.git
7
+ Project-URL: Issues, https://github.com/finizi-app/finizi-agentize/issues
8
+ Author-email: Finizi Engineering <engineering@finizi.app>
9
+ License-Expression: LicenseRef-Proprietary
10
+ License-File: LICENSE
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: Financial and Insurance Industry
15
+ Classifier: License :: Other/Proprietary License
16
+ Classifier: Operating System :: MacOS
17
+ Classifier: Operating System :: POSIX :: Linux
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Topic :: Office/Business :: Financial
22
+ Classifier: Topic :: Office/Business :: Financial :: Accounting
23
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
+ Requires-Python: >=3.11
25
+ Requires-Dist: httpx>=0.28.1
26
+ Requires-Dist: keyring>=25.0.0
27
+ Requires-Dist: keytar>=0.1.0; sys_platform == 'darwin' or sys_platform == 'linux'
28
+ Requires-Dist: mcp<3,>=2
29
+ Requires-Dist: pydantic-settings>=2.10.1
30
+ Requires-Dist: pydantic>=2.11.7
31
+ Requires-Dist: python-dotenv>=1.0.0
32
+ Requires-Dist: rich>=13.9.0
33
+ Requires-Dist: starlette>=0.41.0
34
+ Requires-Dist: tenacity>=9.0.0
35
+ Requires-Dist: typer>=0.15.0
36
+ Requires-Dist: uvicorn>=0.35.0
37
+ Provides-Extra: dev
38
+ Requires-Dist: anyio>=4.6.0; extra == 'dev'
39
+ Requires-Dist: mypy>=1.13.0; extra == 'dev'
40
+ Requires-Dist: pytest-asyncio>=1.1.0; extra == 'dev'
41
+ Requires-Dist: pytest-cov>=6.0.0; extra == 'dev'
42
+ Requires-Dist: pytest>=8.4.1; extra == 'dev'
43
+ Requires-Dist: respx>=0.21.0; extra == 'dev'
44
+ Requires-Dist: ruff>=0.7.0; extra == 'dev'
45
+ Requires-Dist: trustme>=1.2.0; extra == 'dev'
46
+ Description-Content-Type: text/markdown
47
+
48
+ # finizi-app-agent
49
+
50
+ CLI + MCP server for the [finizi-app-api](../README.md) Vietnamese
51
+ accounting, tax, payroll, and operations platform — built to work with the
52
+ [admin.finizi.ai](https://admin.finizi.ai) application.
53
+
54
+ **Private distribution only** — not published to public PyPI.
55
+
56
+ ## What it is
57
+
58
+ `finizi-app-agent` is a thin wrapper that exposes **96** carefully-chosen
59
+ workflows of the finizi-app-api as:
60
+
61
+ 1. **`finizi-app` CLI** — a scriptable command-line tool with stable JSON
62
+ output
63
+ 2. **MCP server** — agent-callable tools via stdio or Streamable HTTP
64
+
65
+ Both surfaces share a single `core/` package, so the same business logic
66
+ is exercised in tests, CLI, and MCP.
67
+
68
+ The wrapper targets the **production admin.finizi.ai application by
69
+ default** but every endpoint is fully configurable through the credential
70
+ resolution chain.
71
+
72
+ ## Install
73
+
74
+ ```bash
75
+ # Editable install (development)
76
+ uv pip install -e .
77
+
78
+ # Internal distribution (from this monorepo's git URL)
79
+ pip install "git+ssh://git@github.com/finizi-app/finizi-agentize.git@<SHA>#subdirectory=finizi-app"
80
+
81
+ # With dev extras (pytest, ruff, mypy)
82
+ pip install "git+ssh://git@github.com/finizi-app/finizi-agentize.git@<SHA>#subdirectory=finizi-app[dev]"
83
+ ```
84
+
85
+ The `finizi-app` CLI and `finizi-app-mcp` entry points are auto-installed.
86
+
87
+ ## What's new (2026-06-30 session)
88
+
89
+ Three additive CLI usability improvements:
90
+
91
+ | Change | Purpose |
92
+ |--------|---------|
93
+ | `finizi-app --version` flag | Print finizi-app + python version, exit 0 |
94
+ | `finizi-app auth status [--json]` | Show masked credentials + source layer (no API call) |
95
+ | `apikeys` file at CWD | New resolution layer for `api_key` (single-line raw key, `# comments` and blank lines tolerated; override via `FINIZI_APIKEYS_PATH`) |
96
+
97
+ Run `finizi-app --version` and `finizi-app auth status` after install to verify
98
+ the upgrade took effect.
99
+
100
+ ## What's new (2026-06-27 session)
101
+
102
+ 8 new audit-skill read-only commands were added to support the
103
+ `review-invoice-and-entries` skill workflow:
104
+
105
+ | Command | Purpose | Phase |
106
+ |---------|---------|-------|
107
+ | `finizi-app invoices get` | Invoice detail by id | 01 |
108
+ | `finizi-app vendors get` | Vendor detail by tax_id (entity-scoped) | 01 |
109
+ | `finizi-app tax check-status` | Tax-code status (currently mock; backend B5 pending) | 01 |
110
+ | `finizi-app ledger get-entries` | GL (journal) entries for an invoice | 01 |
111
+ | `finizi-app documents list` | Documents attached to an entity | 01 |
112
+ | `finizi-app company get` | Buyer company record by tax code (B1 backend) | 02 |
113
+ | `finizi-app payments get-by-invoice` | All payments against an invoice (B2 backend) | 02 |
114
+ | `finizi-app inventory get-receipt` | GRN linked to an invoice (B4 backend) | 02 |
115
+
116
+ All 8 are read-only. All 8 honor `--json`. All 8 use the standard exit
117
+ codes (0/1/2/3/4) defined in [`docs/cli.md`](docs/cli.md).
118
+
119
+ Backend ticket [#1443](https://github.com/finizi-app/b4b-api/issues/1443)
120
+ fixed the `documents list --ref-id` filter; flag is exposed in the CLI.
121
+
122
+ ## What's new (2026-06-28, slice 3)
123
+
124
+ `finizi-app coa get` now returns **raw account state only** — no
125
+ regulatory classification. Closes issue #9.
126
+
127
+ **BREAKING**: removed `source`, `account_regime` (per account), and the
128
+ top-level `regime` field. Renamed `is_custom_account` →
129
+ `is_entity_specific_account` in the response. The wrapper no longer
130
+ performs the second round trip to `/accounting-models`. Finizi is a
131
+ data transport, not a regulatory authority; auditors / skill agents
132
+ apply their own classification against Vietnamese accounting
133
+ regulations.
134
+
135
+ ## What's new (2026-06-28, slice 2)
136
+
137
+ `finizi-app coa get` upgraded to return **all postable accounts** (cấp 1 +
138
+ cấp 2/3 sub-accounts like TK 3311, 3318, 13311-13313) with correct
139
+ `parent_account_id` linking. Backed by `/chart-of-accounts/postable` (slice 1
140
+ used `/chart-of-accounts` which only returned cấp 1).
141
+
142
+ **BREAKING**: `--page` and `--per-page` flags were removed (pagination is
143
+ trivial now — `/postable` returns the full set in one round trip). Users
144
+ who scripted `coa get --page 2` should remove the flag.
145
+
146
+ Adds:
147
+ - `--levels 1,2,3|all` filter (default = all)
148
+ - `--include-inactive` flag (forward-compatible; backend doesn't expose
149
+ inactive accounts yet — see [b4b-api#1483](https://github.com/finizi-app/b4b-api/issues/1483))
150
+ - `source` field now returns `"standard_tt<regime>"` for non-custom accounts
151
+ (was `"unknown"`); `"custom_entity"` for `is_custom_account=true`
152
+ - Pagination metadata: `total`, `page`, `per_page`, `pages`, `has_next`,
153
+ `has_prev` (always single-page; backend returns full set in one shot)
154
+
155
+ Closes gaps 1, 2, 3, 4 from issue #5 against PATEDELI (110 accounts, 73
156
+ sub-accounts, all properly tagged). Gap 5 (true `regime_mismatch`) partially
157
+ addressed — full support pending [b4b-api#1482](https://github.com/finizi-app/b4b-api/issues/1482)
158
+ (`linked_regime` field per account).
159
+
160
+ ## What's new (2026-06-28, slice 1)
161
+
162
+ Added `finizi-app coa get` for the `audit-coa-organization` skill in
163
+ `finizi_bpo_knowledge`. Returns the entity's Chart of Accounts with
164
+ `account_regime` derived from the assigned accounting model. Read-only;
165
+ 2 backend round trips composed client-side.
166
+
167
+ Backend ticket [b4b-api#1479](https://github.com/finizi-app/b4b-api/issues/1479)
168
+ filed for `type` / `source` / `linked_regime` tagging per account — wrapper
169
+ emits `null` / `unknown` until that lands.
170
+
171
+ ## Endpoint configuration
172
+
173
+ The CLI/MCP client talks to a finizi-app-api backend. By default it
174
+ targets the production admin.finizi.ai application. Override through
175
+ any of:
176
+
177
+ | Layer | Variable | Example |
178
+ |-------|----------|---------|
179
+ | Flag (CLI) | `--api-url` | `finizi-app doctor --api-url https://staging.admin.finizi.ai` |
180
+ | Process env | `FINIZI_API_URL` | `export FINIZI_API_URL=https://staging.admin.finizi.ai` |
181
+ | `.env.local` | `FINIZI_API_URL=...` | per-developer override |
182
+ | `.env.<FINIZI_ENV>` | same | per-environment |
183
+ | `.env` | same | shared default |
184
+ | User config | `~/.config/finizi-app/credentials.json` | `{"api_url": "..."}` |
185
+ | Project config | `./.finizi-app/credentials.json` | same |
186
+ | OS keychain | `finizi-app-agent/api_url` | `security add-generic-password -s finizi-app-agent -a api_url -w 'https://...'` |
187
+ | **Default** | built-in | `https://admin.finizi.ai` |
188
+
189
+ `FINIZI_MCP_URL` is also configurable; it defaults to `{api_url}/mcp`.
190
+
191
+ `finizi-app doctor --json` reports which layer resolved without printing
192
+ values.
193
+
194
+ ## Quick start
195
+
196
+ ```bash
197
+ # Check the API is reachable (uses default https://admin.finizi.ai)
198
+ finizi-app doctor
199
+
200
+ # Override for staging
201
+ FINIZI_API_URL=https://staging.admin.finizi.ai finizi-app doctor
202
+
203
+ # Authenticate (caches to OS keychain)
204
+ finizi-app auth login --phone +84xxxxxxxxx --password '...'
205
+
206
+ # Pick a tenant
207
+ finizi-app entities use --entity-id 42
208
+
209
+ # Run a workflow
210
+ finizi-app invoices list --entity-id 42 --page 1
211
+ finizi-app invoices import-xml --entity-id 42 ./invoice.xml
212
+ finizi-app einvoice issue --entity-id 42 --invoice-id 1234
213
+
214
+ # Audit-skill workflows
215
+ finizi-app invoices get --entity-id 42 --invoice-id 1234
216
+ finizi-app ledger get-entries --entity-id 42 --invoice-id 1234
217
+ finizi-app tax check-status --tax-code 0123456789 --date 2026-01-15
218
+ ```
219
+
220
+ ## MCP server
221
+
222
+ ```bash
223
+ # stdio (for local Claude Code / Cursor) — connects to admin.finizi.ai by default
224
+ finizi-app-mcp --transport stdio
225
+
226
+ # Streamable HTTP (self-hosted MCP server, e.g. alongside the admin app)
227
+ finizi-app-mcp --transport http --host 0.0.0.0 --port 8080 --bearer-token "$FINIZI_MCP_BEARER_TOKEN"
228
+ ```
229
+
230
+ See [`docs/cli.md`](docs/cli.md) and [`docs/mcp.md`](docs/mcp.md) for full reference.
231
+
232
+ ## Architecture
233
+
234
+ ```
235
+ finizi-app-agent/
236
+ ├── core/ # framework-agnostic (no typer, no mcp)
237
+ ├── cli/ # Typer app, thin adapter over core
238
+ ├── mcp/ # FastMCP server, thin adapter over core
239
+ └── tests/
240
+ ```
241
+
242
+ See [`docs/architecture.md`](docs/architecture.md) for details.
243
+
244
+ ## Naming
245
+
246
+ | What | Name |
247
+ |------|------|
248
+ | Python import package | `finizi_app` |
249
+ | CLI entry point | `finizi-app` |
250
+ | MCP server entry point | `finizi-app-mcp` |
251
+
252
+ ## License
253
+
254
+ Proprietary — Finizi Engineering. Internal use only.
@@ -0,0 +1,207 @@
1
+ # finizi-app-agent
2
+
3
+ CLI + MCP server for the [finizi-app-api](../README.md) Vietnamese
4
+ accounting, tax, payroll, and operations platform — built to work with the
5
+ [admin.finizi.ai](https://admin.finizi.ai) application.
6
+
7
+ **Private distribution only** — not published to public PyPI.
8
+
9
+ ## What it is
10
+
11
+ `finizi-app-agent` is a thin wrapper that exposes **96** carefully-chosen
12
+ workflows of the finizi-app-api as:
13
+
14
+ 1. **`finizi-app` CLI** — a scriptable command-line tool with stable JSON
15
+ output
16
+ 2. **MCP server** — agent-callable tools via stdio or Streamable HTTP
17
+
18
+ Both surfaces share a single `core/` package, so the same business logic
19
+ is exercised in tests, CLI, and MCP.
20
+
21
+ The wrapper targets the **production admin.finizi.ai application by
22
+ default** but every endpoint is fully configurable through the credential
23
+ resolution chain.
24
+
25
+ ## Install
26
+
27
+ ```bash
28
+ # Editable install (development)
29
+ uv pip install -e .
30
+
31
+ # Internal distribution (from this monorepo's git URL)
32
+ pip install "git+ssh://git@github.com/finizi-app/finizi-agentize.git@<SHA>#subdirectory=finizi-app"
33
+
34
+ # With dev extras (pytest, ruff, mypy)
35
+ pip install "git+ssh://git@github.com/finizi-app/finizi-agentize.git@<SHA>#subdirectory=finizi-app[dev]"
36
+ ```
37
+
38
+ The `finizi-app` CLI and `finizi-app-mcp` entry points are auto-installed.
39
+
40
+ ## What's new (2026-06-30 session)
41
+
42
+ Three additive CLI usability improvements:
43
+
44
+ | Change | Purpose |
45
+ |--------|---------|
46
+ | `finizi-app --version` flag | Print finizi-app + python version, exit 0 |
47
+ | `finizi-app auth status [--json]` | Show masked credentials + source layer (no API call) |
48
+ | `apikeys` file at CWD | New resolution layer for `api_key` (single-line raw key, `# comments` and blank lines tolerated; override via `FINIZI_APIKEYS_PATH`) |
49
+
50
+ Run `finizi-app --version` and `finizi-app auth status` after install to verify
51
+ the upgrade took effect.
52
+
53
+ ## What's new (2026-06-27 session)
54
+
55
+ 8 new audit-skill read-only commands were added to support the
56
+ `review-invoice-and-entries` skill workflow:
57
+
58
+ | Command | Purpose | Phase |
59
+ |---------|---------|-------|
60
+ | `finizi-app invoices get` | Invoice detail by id | 01 |
61
+ | `finizi-app vendors get` | Vendor detail by tax_id (entity-scoped) | 01 |
62
+ | `finizi-app tax check-status` | Tax-code status (currently mock; backend B5 pending) | 01 |
63
+ | `finizi-app ledger get-entries` | GL (journal) entries for an invoice | 01 |
64
+ | `finizi-app documents list` | Documents attached to an entity | 01 |
65
+ | `finizi-app company get` | Buyer company record by tax code (B1 backend) | 02 |
66
+ | `finizi-app payments get-by-invoice` | All payments against an invoice (B2 backend) | 02 |
67
+ | `finizi-app inventory get-receipt` | GRN linked to an invoice (B4 backend) | 02 |
68
+
69
+ All 8 are read-only. All 8 honor `--json`. All 8 use the standard exit
70
+ codes (0/1/2/3/4) defined in [`docs/cli.md`](docs/cli.md).
71
+
72
+ Backend ticket [#1443](https://github.com/finizi-app/b4b-api/issues/1443)
73
+ fixed the `documents list --ref-id` filter; flag is exposed in the CLI.
74
+
75
+ ## What's new (2026-06-28, slice 3)
76
+
77
+ `finizi-app coa get` now returns **raw account state only** — no
78
+ regulatory classification. Closes issue #9.
79
+
80
+ **BREAKING**: removed `source`, `account_regime` (per account), and the
81
+ top-level `regime` field. Renamed `is_custom_account` →
82
+ `is_entity_specific_account` in the response. The wrapper no longer
83
+ performs the second round trip to `/accounting-models`. Finizi is a
84
+ data transport, not a regulatory authority; auditors / skill agents
85
+ apply their own classification against Vietnamese accounting
86
+ regulations.
87
+
88
+ ## What's new (2026-06-28, slice 2)
89
+
90
+ `finizi-app coa get` upgraded to return **all postable accounts** (cấp 1 +
91
+ cấp 2/3 sub-accounts like TK 3311, 3318, 13311-13313) with correct
92
+ `parent_account_id` linking. Backed by `/chart-of-accounts/postable` (slice 1
93
+ used `/chart-of-accounts` which only returned cấp 1).
94
+
95
+ **BREAKING**: `--page` and `--per-page` flags were removed (pagination is
96
+ trivial now — `/postable` returns the full set in one round trip). Users
97
+ who scripted `coa get --page 2` should remove the flag.
98
+
99
+ Adds:
100
+ - `--levels 1,2,3|all` filter (default = all)
101
+ - `--include-inactive` flag (forward-compatible; backend doesn't expose
102
+ inactive accounts yet — see [b4b-api#1483](https://github.com/finizi-app/b4b-api/issues/1483))
103
+ - `source` field now returns `"standard_tt<regime>"` for non-custom accounts
104
+ (was `"unknown"`); `"custom_entity"` for `is_custom_account=true`
105
+ - Pagination metadata: `total`, `page`, `per_page`, `pages`, `has_next`,
106
+ `has_prev` (always single-page; backend returns full set in one shot)
107
+
108
+ Closes gaps 1, 2, 3, 4 from issue #5 against PATEDELI (110 accounts, 73
109
+ sub-accounts, all properly tagged). Gap 5 (true `regime_mismatch`) partially
110
+ addressed — full support pending [b4b-api#1482](https://github.com/finizi-app/b4b-api/issues/1482)
111
+ (`linked_regime` field per account).
112
+
113
+ ## What's new (2026-06-28, slice 1)
114
+
115
+ Added `finizi-app coa get` for the `audit-coa-organization` skill in
116
+ `finizi_bpo_knowledge`. Returns the entity's Chart of Accounts with
117
+ `account_regime` derived from the assigned accounting model. Read-only;
118
+ 2 backend round trips composed client-side.
119
+
120
+ Backend ticket [b4b-api#1479](https://github.com/finizi-app/b4b-api/issues/1479)
121
+ filed for `type` / `source` / `linked_regime` tagging per account — wrapper
122
+ emits `null` / `unknown` until that lands.
123
+
124
+ ## Endpoint configuration
125
+
126
+ The CLI/MCP client talks to a finizi-app-api backend. By default it
127
+ targets the production admin.finizi.ai application. Override through
128
+ any of:
129
+
130
+ | Layer | Variable | Example |
131
+ |-------|----------|---------|
132
+ | Flag (CLI) | `--api-url` | `finizi-app doctor --api-url https://staging.admin.finizi.ai` |
133
+ | Process env | `FINIZI_API_URL` | `export FINIZI_API_URL=https://staging.admin.finizi.ai` |
134
+ | `.env.local` | `FINIZI_API_URL=...` | per-developer override |
135
+ | `.env.<FINIZI_ENV>` | same | per-environment |
136
+ | `.env` | same | shared default |
137
+ | User config | `~/.config/finizi-app/credentials.json` | `{"api_url": "..."}` |
138
+ | Project config | `./.finizi-app/credentials.json` | same |
139
+ | OS keychain | `finizi-app-agent/api_url` | `security add-generic-password -s finizi-app-agent -a api_url -w 'https://...'` |
140
+ | **Default** | built-in | `https://admin.finizi.ai` |
141
+
142
+ `FINIZI_MCP_URL` is also configurable; it defaults to `{api_url}/mcp`.
143
+
144
+ `finizi-app doctor --json` reports which layer resolved without printing
145
+ values.
146
+
147
+ ## Quick start
148
+
149
+ ```bash
150
+ # Check the API is reachable (uses default https://admin.finizi.ai)
151
+ finizi-app doctor
152
+
153
+ # Override for staging
154
+ FINIZI_API_URL=https://staging.admin.finizi.ai finizi-app doctor
155
+
156
+ # Authenticate (caches to OS keychain)
157
+ finizi-app auth login --phone +84xxxxxxxxx --password '...'
158
+
159
+ # Pick a tenant
160
+ finizi-app entities use --entity-id 42
161
+
162
+ # Run a workflow
163
+ finizi-app invoices list --entity-id 42 --page 1
164
+ finizi-app invoices import-xml --entity-id 42 ./invoice.xml
165
+ finizi-app einvoice issue --entity-id 42 --invoice-id 1234
166
+
167
+ # Audit-skill workflows
168
+ finizi-app invoices get --entity-id 42 --invoice-id 1234
169
+ finizi-app ledger get-entries --entity-id 42 --invoice-id 1234
170
+ finizi-app tax check-status --tax-code 0123456789 --date 2026-01-15
171
+ ```
172
+
173
+ ## MCP server
174
+
175
+ ```bash
176
+ # stdio (for local Claude Code / Cursor) — connects to admin.finizi.ai by default
177
+ finizi-app-mcp --transport stdio
178
+
179
+ # Streamable HTTP (self-hosted MCP server, e.g. alongside the admin app)
180
+ finizi-app-mcp --transport http --host 0.0.0.0 --port 8080 --bearer-token "$FINIZI_MCP_BEARER_TOKEN"
181
+ ```
182
+
183
+ See [`docs/cli.md`](docs/cli.md) and [`docs/mcp.md`](docs/mcp.md) for full reference.
184
+
185
+ ## Architecture
186
+
187
+ ```
188
+ finizi-app-agent/
189
+ ├── core/ # framework-agnostic (no typer, no mcp)
190
+ ├── cli/ # Typer app, thin adapter over core
191
+ ├── mcp/ # FastMCP server, thin adapter over core
192
+ └── tests/
193
+ ```
194
+
195
+ See [`docs/architecture.md`](docs/architecture.md) for details.
196
+
197
+ ## Naming
198
+
199
+ | What | Name |
200
+ |------|------|
201
+ | Python import package | `finizi_app` |
202
+ | CLI entry point | `finizi-app` |
203
+ | MCP server entry point | `finizi-app-mcp` |
204
+
205
+ ## License
206
+
207
+ Proprietary — Finizi Engineering. Internal use only.