Metadata-Version: 2.4
Name: finizi-app
Version: 0.1.0
Summary: CLI + MCP server for the Finizi.AI Vietnamese accounting/tax platform
Project-URL: Homepage, https://github.com/finizi-app/finizi-agentize
Project-URL: Repository, https://github.com/finizi-app/finizi-agentize.git
Project-URL: Issues, https://github.com/finizi-app/finizi-agentize/issues
Author-email: Finizi Engineering <engineering@finizi.app>
License-Expression: LicenseRef-Proprietary
License-File: LICENSE
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Financial and Insurance Industry
Classifier: License :: Other/Proprietary License
Classifier: Operating System :: MacOS
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Office/Business :: Financial
Classifier: Topic :: Office/Business :: Financial :: Accounting
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.11
Requires-Dist: httpx>=0.28.1
Requires-Dist: keyring>=25.0.0
Requires-Dist: keytar>=0.1.0; sys_platform == 'darwin' or sys_platform == 'linux'
Requires-Dist: mcp<3,>=2
Requires-Dist: pydantic-settings>=2.10.1
Requires-Dist: pydantic>=2.11.7
Requires-Dist: python-dotenv>=1.0.0
Requires-Dist: rich>=13.9.0
Requires-Dist: starlette>=0.41.0
Requires-Dist: tenacity>=9.0.0
Requires-Dist: typer>=0.15.0
Requires-Dist: uvicorn>=0.35.0
Provides-Extra: dev
Requires-Dist: anyio>=4.6.0; extra == 'dev'
Requires-Dist: mypy>=1.13.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=1.1.0; extra == 'dev'
Requires-Dist: pytest-cov>=6.0.0; extra == 'dev'
Requires-Dist: pytest>=8.4.1; extra == 'dev'
Requires-Dist: respx>=0.21.0; extra == 'dev'
Requires-Dist: ruff>=0.7.0; extra == 'dev'
Requires-Dist: trustme>=1.2.0; extra == 'dev'
Description-Content-Type: text/markdown

# finizi-app-agent

CLI + MCP server for the [finizi-app-api](../README.md) Vietnamese
accounting, tax, payroll, and operations platform — built to work with the
[admin.finizi.ai](https://admin.finizi.ai) application.

**Private distribution only** — not published to public PyPI.

## What it is

`finizi-app-agent` is a thin wrapper that exposes **96** carefully-chosen
workflows of the finizi-app-api as:

1. **`finizi-app` CLI** — a scriptable command-line tool with stable JSON
   output
2. **MCP server** — agent-callable tools via stdio or Streamable HTTP

Both surfaces share a single `core/` package, so the same business logic
is exercised in tests, CLI, and MCP.

The wrapper targets the **production admin.finizi.ai application by
default** but every endpoint is fully configurable through the credential
resolution chain.

## Install

```bash
# Editable install (development)
uv pip install -e .

# Internal distribution (from this monorepo's git URL)
pip install "git+ssh://git@github.com/finizi-app/finizi-agentize.git@<SHA>#subdirectory=finizi-app"

# With dev extras (pytest, ruff, mypy)
pip install "git+ssh://git@github.com/finizi-app/finizi-agentize.git@<SHA>#subdirectory=finizi-app[dev]"
```

The `finizi-app` CLI and `finizi-app-mcp` entry points are auto-installed.

## What's new (2026-06-30 session)

Three additive CLI usability improvements:

| Change | Purpose |
|--------|---------|
| `finizi-app --version` flag | Print finizi-app + python version, exit 0 |
| `finizi-app auth status [--json]` | Show masked credentials + source layer (no API call) |
| `apikeys` file at CWD | New resolution layer for `api_key` (single-line raw key, `# comments` and blank lines tolerated; override via `FINIZI_APIKEYS_PATH`) |

Run `finizi-app --version` and `finizi-app auth status` after install to verify
the upgrade took effect.

## What's new (2026-06-27 session)

8 new audit-skill read-only commands were added to support the
`review-invoice-and-entries` skill workflow:

| Command | Purpose | Phase |
|---------|---------|-------|
| `finizi-app invoices get` | Invoice detail by id | 01 |
| `finizi-app vendors get` | Vendor detail by tax_id (entity-scoped) | 01 |
| `finizi-app tax check-status` | Tax-code status (currently mock; backend B5 pending) | 01 |
| `finizi-app ledger get-entries` | GL (journal) entries for an invoice | 01 |
| `finizi-app documents list` | Documents attached to an entity | 01 |
| `finizi-app company get` | Buyer company record by tax code (B1 backend) | 02 |
| `finizi-app payments get-by-invoice` | All payments against an invoice (B2 backend) | 02 |
| `finizi-app inventory get-receipt` | GRN linked to an invoice (B4 backend) | 02 |

All 8 are read-only. All 8 honor `--json`. All 8 use the standard exit
codes (0/1/2/3/4) defined in [`docs/cli.md`](docs/cli.md).

Backend ticket [#1443](https://github.com/finizi-app/b4b-api/issues/1443)
fixed the `documents list --ref-id` filter; flag is exposed in the CLI.

## What's new (2026-06-28, slice 3)

`finizi-app coa get` now returns **raw account state only** — no
regulatory classification. Closes issue #9.

**BREAKING**: removed `source`, `account_regime` (per account), and the
top-level `regime` field. Renamed `is_custom_account` →
`is_entity_specific_account` in the response. The wrapper no longer
performs the second round trip to `/accounting-models`. Finizi is a
data transport, not a regulatory authority; auditors / skill agents
apply their own classification against Vietnamese accounting
regulations.

## What's new (2026-06-28, slice 2)

`finizi-app coa get` upgraded to return **all postable accounts** (cấp 1 +
cấp 2/3 sub-accounts like TK 3311, 3318, 13311-13313) with correct
`parent_account_id` linking. Backed by `/chart-of-accounts/postable` (slice 1
used `/chart-of-accounts` which only returned cấp 1).

**BREAKING**: `--page` and `--per-page` flags were removed (pagination is
trivial now — `/postable` returns the full set in one round trip). Users
who scripted `coa get --page 2` should remove the flag.

Adds:
- `--levels 1,2,3|all` filter (default = all)
- `--include-inactive` flag (forward-compatible; backend doesn't expose
  inactive accounts yet — see [b4b-api#1483](https://github.com/finizi-app/b4b-api/issues/1483))
- `source` field now returns `"standard_tt<regime>"` for non-custom accounts
  (was `"unknown"`); `"custom_entity"` for `is_custom_account=true`
- Pagination metadata: `total`, `page`, `per_page`, `pages`, `has_next`,
  `has_prev` (always single-page; backend returns full set in one shot)

Closes gaps 1, 2, 3, 4 from issue #5 against PATEDELI (110 accounts, 73
sub-accounts, all properly tagged). Gap 5 (true `regime_mismatch`) partially
addressed — full support pending [b4b-api#1482](https://github.com/finizi-app/b4b-api/issues/1482)
(`linked_regime` field per account).

## What's new (2026-06-28, slice 1)

Added `finizi-app coa get` for the `audit-coa-organization` skill in
`finizi_bpo_knowledge`. Returns the entity's Chart of Accounts with
`account_regime` derived from the assigned accounting model. Read-only;
2 backend round trips composed client-side.

Backend ticket [b4b-api#1479](https://github.com/finizi-app/b4b-api/issues/1479)
filed for `type` / `source` / `linked_regime` tagging per account — wrapper
emits `null` / `unknown` until that lands.

## Endpoint configuration

The CLI/MCP client talks to a finizi-app-api backend. By default it
targets the production admin.finizi.ai application. Override through
any of:

| Layer | Variable | Example |
|-------|----------|---------|
| Flag (CLI) | `--api-url` | `finizi-app doctor --api-url https://staging.admin.finizi.ai` |
| Process env | `FINIZI_API_URL` | `export FINIZI_API_URL=https://staging.admin.finizi.ai` |
| `.env.local` | `FINIZI_API_URL=...` | per-developer override |
| `.env.<FINIZI_ENV>` | same | per-environment |
| `.env` | same | shared default |
| User config | `~/.config/finizi-app/credentials.json` | `{"api_url": "..."}` |
| Project config | `./.finizi-app/credentials.json` | same |
| OS keychain | `finizi-app-agent/api_url` | `security add-generic-password -s finizi-app-agent -a api_url -w 'https://...'` |
| **Default** | built-in | `https://admin.finizi.ai` |

`FINIZI_MCP_URL` is also configurable; it defaults to `{api_url}/mcp`.

`finizi-app doctor --json` reports which layer resolved without printing
values.

## Quick start

```bash
# Check the API is reachable (uses default https://admin.finizi.ai)
finizi-app doctor

# Override for staging
FINIZI_API_URL=https://staging.admin.finizi.ai finizi-app doctor

# Authenticate (caches to OS keychain)
finizi-app auth login --phone +84xxxxxxxxx --password '...'

# Pick a tenant
finizi-app entities use --entity-id 42

# Run a workflow
finizi-app invoices list --entity-id 42 --page 1
finizi-app invoices import-xml --entity-id 42 ./invoice.xml
finizi-app einvoice issue --entity-id 42 --invoice-id 1234

# Audit-skill workflows
finizi-app invoices get --entity-id 42 --invoice-id 1234
finizi-app ledger get-entries --entity-id 42 --invoice-id 1234
finizi-app tax check-status --tax-code 0123456789 --date 2026-01-15
```

## MCP server

```bash
# stdio (for local Claude Code / Cursor) — connects to admin.finizi.ai by default
finizi-app-mcp --transport stdio

# Streamable HTTP (self-hosted MCP server, e.g. alongside the admin app)
finizi-app-mcp --transport http --host 0.0.0.0 --port 8080 --bearer-token "$FINIZI_MCP_BEARER_TOKEN"
```

See [`docs/cli.md`](docs/cli.md) and [`docs/mcp.md`](docs/mcp.md) for full reference.

## Architecture

```
finizi-app-agent/
├── core/         # framework-agnostic (no typer, no mcp)
├── cli/          # Typer app, thin adapter over core
├── mcp/          # FastMCP server, thin adapter over core
└── tests/
```

See [`docs/architecture.md`](docs/architecture.md) for details.

## Naming

| What | Name |
|------|------|
| Python import package | `finizi_app` |
| CLI entry point | `finizi-app` |
| MCP server entry point | `finizi-app-mcp` |

## License

Proprietary — Finizi Engineering. Internal use only.