Metadata-Version: 2.4
Name: 3sat
Version: 0.1.1
Summary: Command line client for the 3SAT protocol.
Author: 3SAT Lab
License-Expression: MIT
Project-URL: Homepage, https://3sat.network/
Project-URL: Documentation, https://3sat.network/docs/api
Project-URL: Application, https://3sat.network/app
Project-URL: Source, https://github.com/spencerg-sys/3sat-cli
Keywords: 3sat,sat,web3,cnf,bounty
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests>=2.31.0
Requires-Dist: web3<8,>=6.20.0
Requires-Dist: eth-account>=0.10.0
Requires-Dist: pycryptodome>=3.20.0
Dynamic: license-file

# 3SAT CLI

Official command line client for the 3SAT protocol.

The package installs a `3sat` command for users who want to search the answer database, create bounties, buy answer access, and download answer bundles without using the web UI.

## Links

- Website: https://3sat.network/
- Web app: https://3sat.network/app
- Protocol docs: https://3sat.network/docs/api
- SAT Academy: https://3sat.network/docs/academy

## Install

Python 3.10 or newer is required. Install the published CLI in your Python environment:

```bash
python -m pip install --upgrade 3sat
```

Verify the installation:

```bash
3sat --version
3sat --help
3sat doctor
```

The wheel embeds its own Python implementation of the
`3sat-dimacs-strict-v1` parser plus the shared conformance corpus. It does not
need the TypeScript core or Node.js at runtime. File-based CNF commands validate
bounded raw bytes locally before configuration, wallet, or network operations;
SAT artifacts must additionally be non-conflicting unit-clause assignments.

## Security

Use a dedicated protocol wallet. Do not use your main wallet.

The CLI does not store private keys by default. Pass a private key with `--private-key`, or set:

```bash
export THREESAT_PRIVATE_KEY=0x...
```

On PowerShell:

```powershell
$env:THREESAT_PRIVATE_KEY="0x..."
```

## Quickstart

Show current configuration:

```bash
3sat config show
```

Initialize the default public deployment configuration:

```bash
3sat config init
```

The bundled defaults target the production deployment on Arbitrum One (chain ID `42161`). Existing `~/.3sat/config.json` files are not overwritten by source-default changes; preserve intentional custom values, then replace every public deployment field with `3sat config set` before connecting to production.

Search for an existing answer:

```bash
3sat search problem.cnf
```

Check the configured API, RPC, contracts, tokens, and optional wallet balances:

```bash
3sat doctor --address 0xYourWallet
3sat tokens --onchain
```

Create a bounty. The command accepts a DIMACS CNF instance up to **256 MiB**, validates/hashes it incrementally, uploads an immutable snapshot directly to R2 in 8 MiB parts, and waits for background validation before preparing the bounty. File bytes do not pass through Vercel. Upload authorization requires the issuer's wallet key even without `--send`; this is an off-chain signature and does not spend gas. Broadcasting still requires `--send`:

```bash
3sat issue problem.cnf --reward 100 --token USDC --send
```

Before broadcasting, the CLI locally ABI-encodes the expected approval and bounty call, verifies the complete prepared transaction batch (`to`, `data`, and `value`), and signs only the locally reconstructed transactions. Commit and reveal broadcasts use the same fail-closed check.

The CLI currently processes one CNF per `issue` invocation and one artifact per `upload-solution` invocation. It does not provide a built-in batch manifest, directory/glob input, or atomic batch upload/issue command.

The default open, reveal, and verification windows are 1 hour each. Every window must be at least 1 hour. During the official-verifier launch phase, verifier quorum is fixed at 1; `--quorum` is retained for compatibility but rejects every value other than `1`.

Run a true local dry run without uploading files:

```bash
3sat issue problem.cnf --reward 100 --token USDC --dry-run
```

Buy answer access:

```bash
3sat buy-answer SAT-XXXX-XXXX-XXXX --send
```

Download an original finalized bounty bundle:

```bash
3sat download-answer SAT-XXXX-XXXX-XXXX -o answer.zip
```

Download a matched answer for a CNF you searched. SAT assignments may be rebuilt for an equivalent CNF. For a format-normalized or variable-renamed UNSAT match, the service converts the finalized proof in an isolated worker and returns the bundle only after the matching checker accepts the proof against the exact CNF you supplied:

```bash
3sat download-answer SAT-XXXX-XXXX-XXXX --cnf my-query.cnf -o matched-answer.zip
```

Original/raw-exact downloads request a small, access-checked manifest containing signed R2 URLs, sizes and digests. The CLI streams each file to disk, checks its size and Keccak digest, then creates the ZIP locally. Neither a 256 MiB CNF nor a 1 GiB proof is buffered into a Vercel response. Temporary downloads are removed on failure and an existing output ZIP is replaced only after successful verification.

Non-exact UNSAT conversion jobs are asynchronous. The CLI waits up to 60 minutes by default (override with `--transform-timeout-minutes`) and verifies the checker-bound ZIP size and digest while downloading. Interactive non-exact/variable-renaming matching remains a separately bounded operation: CNFs above 3.5 MiB require a raw-exact match; the CLI rejects unsupported large non-exact queries before buying access. Raising the artifact limit does not silently enable unlimited graph-isomorphism processing.

## Large artifacts and resource budgets

This release supports CNFs and SAT assignments up to 256 MiB, UNSAT proofs up to 1 GiB, and answer ZIPs up to 1.5 GiB. The strict DIMACS grammar is unchanged. The shared resource ceilings are 5,000,000 variables, 20,000,000 clauses, 100,000,000 literal occurrences, 25,000,000 physical lines, 1 MiB per physical line, and 5,000,000 literals in one clause. Exceeding a resource budget is not proof that an answer is mathematically invalid.

For CNFs above 3.5 MiB, `search` sends only the locally computed raw digest and explicitly uses exact-byte matching. Above the same threshold, `standardize` runs locally and reports `streaming-format-only`: it normalizes DIMACS formatting while preserving clause and literal order. It does not compute or claim the website's sorted canonical/variable-renaming digest. Smaller requests use the separately resource-limited API; being under the byte limit does not guarantee that structural matching is available. Use `-o normalized.cnf` for the resulting file; large JSON output contains a summary rather than the entire CNF text.

Upload snapshots require temporary free disk space of at least the artifact size plus 64 MiB. Manifest downloads require approximately twice the combined file size plus 64 MiB while assembling the ZIP. In-process failures clean up temporary files; an operating-system crash or forced kill can leave OS-temporary `3sat-upload-*` or `.3sat-answer-*` directories. Only remove those after confirming the originating CLI process is stopped. Never remove reveal bundles as part of download cleanup.

Failed R2 parts are retried with the same upload identity. Immediately before completion, the CLI atomically saves a private receipt under the configuration directory's `upload-receipts/` folder (normally `~/.3sat/upload-receipts/`). It contains the scoped upload token, file/wallet/API binding and completed part ETags, never the private key. POSIX permissions are restricted to the user; Windows uses the containing user directory's ACLs. If a completion response is lost or the 30-minute validation wait expires, rerun the same command with the same file, wallet and API configuration: the receipt resumes the existing completed/queued upload instead of uploading another copy. A forced stop before all parts finish is not resumable across CLI processes; that attempt's unfinished server upload expires instead. Pending server reservations expire after 24 hours; failed/expired local receipts are removed individually, while ready receipts and published artifacts are preserved. Receipts are private operational data and must not be included in release packages.

Upload recovery is not transaction recovery: do not rerun `issue --send` blindly if the bounty transaction may already have been broadcast. Check the wallet transaction and bounty first to avoid creating a second bounty. For commit/reveal recovery, preserve and use the existing reveal bundle.

The website, background artifact-validation worker, solver and official verifier must be upgraded together before using these ceilings. A larger byte limit does not guarantee that every instance can be solved or that every proof finishes before the bounty's deadline.

## Commands

- `3sat config show`
- `3sat config init`
- `3sat config set KEY VALUE`
- `3sat doctor`
- `3sat tokens`
- `3sat standardize problem.cnf`
- `3sat search problem.cnf`
- `3sat marketplace` (shows 20 bounties by default)
- `3sat marketplace --offset 20` (load the next page)
- `3sat bounty SAT-...`
- `3sat issue problem.cnf --reward 100 --token USDC --dry-run`
- `3sat issue problem.cnf --reward 100 --token USDC --send`
- `3sat buy-answer SAT-... --send`
- `3sat download-answer SAT-... --cnf query.cnf`
- `3sat balance --address 0x...`
- `3sat upload-solution answer.cnf --kind sat --private-key 0x...`
- `3sat upload-solution proof.frat --kind unsat --proof-format frat --private-key 0x...`
- `3sat prepare-commit SAT-... --solver 0x... --artifact-id artifact-... --solution-digest 0x... -o reveal.json`
- `3sat commit SAT-... --artifact-id artifact-... --solution-digest 0x... --private-key 0x... --send -o reveal.json`
- `3sat reveal --bundle reveal.json --submission-id 1 --private-key 0x... --send`

## Solver flow for advanced users

The fully automated solver clients are still the easiest way to solve bounties. Advanced users can also use the CLI.

Issuer task descriptions are limited to 200 characters. This keeps public metadata concise and prevents oversized bounty descriptions from being used as an abuse vector.

Upload a SAT answer:

```bash
3sat upload-solution answer.cnf --kind sat --private-key 0x...
```

Upload an UNSAT proof:

```bash
3sat upload-solution unsat-proof.frat --kind unsat --proof-format frat --private-key 0x...
```

UNSAT proof uploads are limited to 1 GiB; SAT assignments are limited to 256 MiB. Every artifact uses a wallet-authenticated multipart upload and background validation. A lost reservation response is retried with the same signed upload identity, and failed R2 parts are retried independently. `upload-solution` returns only after the artifact is ready; do not commit an unvalidated upload. The private key may be supplied by `--private-key` or `THREESAT_PRIVATE_KEY`.

Upload `ready` means the storage, size and digest checks (and applicable CNF/assignment format checks) completed. It does not mean an UNSAT proof has already been accepted as mathematically correct: the official verifier checks the proof after commit and reveal. Choose `--kind unsat --proof-format drat|frat|lrat` to match the actual proof format, and pass the same kind and format to `prepare-commit` or `commit`.

Successful solution uploads return an opaque `artifactId`, not an R2 object location. Keep the artifact id and digest for commit and reveal. The artifact id is used only by the API to bind the private upload to the solver; it is not placed on chain and is not included in the commitment hash.

The solver passed to `prepare-commit` must be the same wallet that signed `upload-solution`. A different wallet cannot claim or reveal that private artifact.

Prepare a commit without broadcasting:

```bash
3sat prepare-commit SAT-XXXX-XXXX-XXXX \
  --solver 0xSolverWallet \
  --artifact-id artifact-... \
  --solution-digest 0x... \
  -o reveal.json
```

Broadcast a commit:

```bash
3sat commit SAT-XXXX-XXXX-XXXX \
  --artifact-id artifact-... \
  --solution-digest 0x... \
  --private-key 0x... \
  --send \
  -o reveal.json
```

Before preparing or sending a commit, the CLI verifies the bounty's snapshotted solver bond directly on chain and rebuilds the approval with that value. A snapshot value of zero is rejected.

The commitment binds the chain id, BountyManager address, bounty id, solver, solution kind, proof format, solution digest, and salt. The opaque artifact id stays in the local reveal bundle so the API can recover and verify the private upload binding, but neither commit nor reveal stores it on chain.

For `commit --send`, the CLI writes the reveal bundle atomically before broadcasting any approval or commit. Without `-o`, it uses `data/reveal-bundles/bounty-<id>-commit-<hash>.json`; if that write fails, nothing is broadcast. The bundle contains the secret salt required to reveal, so keep it durable and private and do not delete, share, sync, upload, or include it in a ZIP until the submission has been revealed.

Reveal after commit. Use the submission id assigned by the commit transaction:

```bash
3sat reveal --bundle reveal.json --submission-id 1 --private-key 0x... --send
```

## Configuration

The config file is stored at:

```text
~/.3sat/config.json
```

Supported environment variable overrides:

- `THREESAT_CONFIG`
- `THREESAT_CONFIG_DIR`
- `THREESAT_API_URL`
- `THREESAT_RPC_URL`
- `THREESAT_CHAIN_ID`
- `THREESAT_CHAIN_NAME`
- `THREESAT_BOUNTY_MANAGER_ADDRESS`
- `THREESAT_ARTIFACT_ACCESS_CONTROLLER_ADDRESS`
- `THREESAT_USDC_ADDRESS`
- `THREESAT_TOKEN_ADDRESS`
- `THREESAT_PRIVATE_KEY`

## Notes

The CLI uses the public 3SAT API for artifact storage, search, metadata generation, and transaction preparation. Wallet signing and transaction broadcasting happen locally on the user's machine.

The solver and verifier automation clients remain separate because they bundle SAT solvers, proof checkers, and long-running polling loops.

## Development

Install from source when contributing to the CLI:

```bash
git clone https://github.com/spencerg-sys/3sat-cli.git
cd 3sat-cli
python -m pip install -e .
```

## Maintainer release checklist: 0.1.1

Version 0.1.1 requires the matching website multipart-upload API, R2 multipart CORS configuration, artifact-validation worker, solver and official verifier rollout. Publishing a Python package does not deploy those services. Do not announce large-upload availability until that coordinated deployment is ready.

From this repository root, use a development virtual environment to test and build:

```bash
python -m pip install --upgrade build twine
python -m pip install -e .
python -m unittest discover -s tests
python -m build
python -m twine check --strict dist/3sat-0.1.1-py3-none-any.whl dist/3sat-0.1.1.tar.gz
```

Check that `pyproject.toml`, `threesat_cli.__version__`, `3sat --version` and both distribution metadata files all say `0.1.1`. Inspect both archives: include the Python modules, parser corpus, license and package metadata; exclude credentials, upload receipts, reveal bundles, caches and local runtime files. `MANIFEST.in` is a packaging instruction file used by the source distribution; keep it in the repository.

Only after the release has been approved, upload these exact two files to production PyPI:

```bash
python -m twine upload --repository pypi dist/3sat-0.1.1-py3-none-any.whl dist/3sat-0.1.1.tar.gz
```

Do not use `dist/*`: older `0.1.0` artifacts may coexist in that folder and must not be uploaded again. PyPI cannot replace already-published release files; if `0.1.1` is already published, use a new version for further changes. Keep publishing credentials outside the repository and distribution archives.

After publication, check installation in a fresh virtual environment:

```bash
python -m pip install --index-url https://pypi.org/simple "3sat==0.1.1"
3sat --version
3sat issue --help
3sat upload-solution --help
```

Installation and help checks do not upload artifacts or send transactions. See the [Python Packaging User Guide](https://packaging.python.org/en/latest/tutorials/packaging-projects/) for the build and publishing workflow.
