Metadata-Version: 2.4
Name: lexgents-cli
Version: 0.1.0
Summary: A thin CLI client for the LexGents research service
License-Expression: LicenseRef-Proprietary
Project-URL: Repository, https://github.com/Tenfold-ai/LexGents-CLI
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# LexGents CLI

A thin Python client for the LexGents research service. The CLI runs locally;
research runs on the operator-configured server. Requires Python 3.10+ and has
no runtime dependencies. Browser login currently supports macOS and Linux.

This repository contains the CLI and a separately distributed Agent Skill.
Neither the wheel nor the source distribution includes the Skill. The package
name is `lexgents-cli`; the executable is `lexgents`. Stable releases use PyPI;
preview packages use TestPyPI. The Skill marketplace release is separate.

## Install

For the first stable release, use an isolated environment with an up-to-date
Python installation, certificate store and pip (26.2.2 or newer):

```bash
python3 -m venv .venv
.venv/bin/python -I -m pip install --isolated --disable-pip-version-check --no-deps 'pip @ https://files.pythonhosted.org/packages/3f/06/3e4420302363fbb71be3c7f35ce042f54bfca330e3e66b3a2e3c4cca579f/pip-26.2.2-py3-none-any.whl#sha256=fd7f4dfa8190e014013b9f08f3e973f4e4c26ffd179a204895533a7254813a70'
.venv/bin/python -m pip install --index-url https://pypi.org/simple/ --no-deps --only-binary=:all: 'lexgents-cli==0.1.0'
.venv/bin/lexgents --version
```

The hash-pinned pip bootstrap applies the
[Python Security CA advisory](https://discuss.python.org/t/information-for-python-users-regarding-emudhra-emsign-ca-certificate-security-incident/109576)
inside the new environment. A newly created venv can contain an older pip even
when the global pip has been updated.

For a preview, use only `https://test.pypi.org/simple/` and the operator's exact
prerelease version, such as `0.1.0rc1`. Do not combine indexes with
`--extra-index-url`. The CLI has no runtime dependencies. An unavailable version
is a release/setup issue, not a reason to substitute a similarly named package.
You can also install an operator-provided, verified wheel using
`pip install --no-index --no-deps /path/to/release.whl`.

Package installation does not select a service environment. Obtain the trusted
production configuration from the service operator; use a separate Dev
configuration and auth directory for development testing.

For development from this repository, use `python -m pip install .` inside a
virtual environment. The remaining examples assume `lexgents` is on `PATH`.

## Configure and sign in

Obtain a trusted service configuration from your operator and keep the active
copy outside this repository. The template `examples/auth.example.json` uses
nonfunctional placeholder domains. It contains the required fields, not a
working deployment or a pre-registered callback. The operator must supply the
exact registered callback and matching service targets.

```bash
export LEXGENTS_AUTH_CONFIG='/path/to/trusted/auth.json'
lexgents login --config "$LEXGENTS_AUTH_CONFIG" --json
lexgents auth status --json
lexgents doctor --json
lexgents billing status --json
```

Complete sign-in and MFA in a browser on the same computer. Login uses
authorization code + PKCE S256, then exchanges the identity token with the
configured backend for an application JWT. The callback listener only runs
during login. `--no-browser` prints a URL for this same computer; remote-device
login is not implemented. Callback support must be verified for the intended
identity-provider configuration before production use.

Credentials are saved in `~/.config/lexgents/session.json`, with directory mode
0700 and file mode 0600. Set `LEXGENTS_AUTH_DIR` to choose a different private
directory and reuse it for every command. This is file storage, not an OS
keychain. The CLI does not print stored token values.

Browser login requires a dedicated CLI Cognito client and a backend supporting
the CLI session policy. Its fixed deadline is eight days after authentication;
refresh never extends it. Application JWTs last at most one hour and are capped
at that deadline by the backend. `session_expires_at` reports the login deadline;
`app_expires_at` reports the current JWT's expiry. Existing Portal clients keep
their own policy. The seven-day trial and Credits rules are independent.

At the deadline, the next authenticated command or `auth status` removes the
local cache and requires a new login. There is no background deletion while the
CLI is closed. Earlier preview caches may require one new login. A backend
response without a CLI-specific session deadline is rejected. Configure and
deploy the service policy before upgrading users.

An expired-session response includes the trusted `top_up_url` when `portal_url`
is configured, with `billing_status=unknown`. The agent may offer this link for
sign-in and billing review; it must not claim payment is required without a fresh
billing check. During day seven to day eight, an otherwise valid login can still
read the expired-trial status and display its normal top-up notice.

The backend selects the existing default organization. `--organization-id`
rejects a different result; it does not grant membership or create an account.
Accounts without an organization use the existing Portal setup flow.

`auth status` reads cached state. Research, doctor and billing checks refresh
credentials when needed; `auth refresh --json` forces refresh. A rejected refresh
requires sign-in again. `logout --json` revokes the Cognito refresh token and
removes local credentials. Already-issued application JWTs remain subject to
their existing expiration, and the browser session is not cleared.

For an operator-issued application JWT, set `LEXGENTS_TOKEN_FILE` to a private
file and `LEXGENTS_ENDPOINT` to the trusted research base URL. Keep
`LEXGENTS_AUTH_CONFIG` set for backend and Portal targets. Alternatively supply
both `LEXGENTS_BACKEND_URL` and `LEXGENTS_PORTAL_URL`.
`LEXGENTS_ACCESS_TOKEN` overrides the token file; either overrides browser-login
credentials. The JWT is sent as `X-Auth: Bearer ...`. An optional
`LANGSMITH_API_KEY` supplies a separate infrastructure header only to the research
service. Credentials are not accepted as command-line arguments, and `.env`
files are not automatically loaded.

## Trial, Credits and top-up

Login and doctor include a billing snapshot. `billing status --json` returns a
fresh one. A completed status check is not permission to research: inspect
`billing.can_use`. `doctor` also checks the endpoint and authenticated assistant
availability; it does not execute research.

Before creating a research thread the CLI reads existing trial, feature
availability and Credits endpoints. It reports the server's trial deadline,
never derives a new seven-day period from login or JWT expiry, and preserves
the existing Portal Credits fallback after trial expiry. Credits thresholds and
deductions remain server-owned. The legacy availability response's overall
`canUse` is retained as `server_availability_can_use` for diagnosis.

- A deadline within one day produces `notice.code=trial_ending_soon`.
- Insufficient eligibility produces exit 9 / `payment_required`, a reason and
  `top_up_url` before research submission. The URL is generated from the trusted
  Portal origin and includes the current organization hint, never a token.
- The user chooses an amount and completes payment in Portal. Recheck billing
  afterward and resume the retained question only when `billing.can_use=true`.
  A successful browser return does not prove Credits have arrived.
- Failed, malformed or inconsistent billing reads produce exit 10 /
  `billing_unavailable`; unknown balance is not a request to pay.

The CLI does not create a checkout, pay, or change billing policy. Client-side
preflight is a usability check; server-side authorization and accounting must
enforce access independently. Login return and organization-mismatch protection
depend on the corresponding Portal version deployed by the operator.

## Research

```bash
lexgents research --query-file question.txt --json > result.json
lexgents research --input-file request.json --json
lexgents research --help
```

Questions are UTF-8 text, at most 2,000 characters. `--query-file -` reads stdin.
`--input-file` accepts an object containing `query`, `jurisdiction`, `language`,
`tool_list`, `max_tool_call_num` and optional `research_mode`, without an `input`
wrapper. A generic example is in `examples/research.json` in the repository.
Input-file mode rejects simultaneous override flags. Default jurisdiction is
Taiwan and language is Traditional Chinese. US jurisdictions require a state.
Optional research profiles are `xhigh` and `ultra`; syntax validation does not
establish service coverage for a jurisdiction.

Each command submits an independent question without conversation history. The
CLI creates a thread, waits for the run, and deletes the thread after a known
outcome. A timeout, disconnect or interruption during research leaves it for
operator investigation. No research is automatically replayed.

## Output and failures

`--json`, or piped stdout, emits one JSON object. Success requires exit 0,
`status=completed` and a nonempty `result.answer`. Source arrays and additional
result metadata are preserved. Inspect the answer and cited authorities;
technical completion is not legal-quality certification.

Errors include `error.code`, `error.message` and `error.outcome_unknown`. Keep
`request_id`, `thread_id` and any `run_id` for investigation. Request IDs are
correlation identifiers, not idempotency keys. When outcome is unknown, the
server may already have run the request; do not automatically resubmit it.

`thread_cleanup=deleted` confirms deletion was accepted, `not_attempted` means
no cleanup request was sent, and `unconfirmed` means cleanup was not confirmed.
Cleanup failure never calls for repeating the research. The default research
socket timeout is 600 seconds, not an overall wall-clock deadline. Stopping the
CLI does not cancel server work. HTTP redirects are refused to keep credentials
at the configured origin.

| Exit | Meaning |
|---|---|
| 0 | Command completed; inspect billing eligibility separately |
| 2 | Usage, input or configuration error |
| 3 | Missing/rejected credentials, access denied or account setup required |
| 4 | Rate limited |
| 5 | API/run failure, redirect, unavailable assistant or required input |
| 6 | Timeout |
| 7 | Connection failure |
| 8 | Invalid response |
| 9 | Payment required; show the returned URL and recheck after payment |
| 10 | Billing unavailable; no preflight-authorized research submitted |
| 130 | Client interrupted |

## Separate Agent Skill

The Skill source lives at `skills/lexgents-research/SKILL.md` in this repository.
It is installed through a Skill distribution channel, independently of Python.
The CLI has no `lexgents skill print/install` commands.
Installing the CLI does not install a Skill; installing a Skill does not supply
credentials or change the agent's shell/network permissions.

The repository documents the distribution options in
`docs/skill-distribution.md`. This is not a claim that the Skill is publicly
listed. Only the CLI's seven Python modules and public package metadata belong
in Python distributions; repository-only examples, tests, research notes and
Skill files are excluded by the build contract.

## License

The CLI is proprietary. The included `LICENSE` permits installation and use to
access authorized LexGents services; other rights are reserved. Public package
availability does not grant an open-source license or service access.

## Development and release checks

From a checkout, with build tools available:

```bash
PYTHONPATH=src python -m unittest discover -s tests -v
python -m build
python scripts/check_release.py dist/lexgents_cli-0.1.0rc1-py3-none-any.whl dist/lexgents_cli-0.1.0rc1.tar.gz
```

Tests use local synthetic OAuth, billing and research fixtures. No real account,
payment, deployment or customer data is required. See `SECURITY.md` for release
boundaries. Review the actual archives before uploading them; `.gitignore` does
not control package contents. The release pipeline uses AWS CodePipeline and
CodeBuild, with an exact reviewed commit, isolated publication credentials, and
a manual approval before public TestPyPI upload. It cannot publish to production
PyPI. Infrastructure and its operator runbook live in `infra/` and
`docs/testpypi-release.md`; neither is included in the distributions.
