mantos 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.
@@ -0,0 +1 @@
1
+ dist/
mantos-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,99 @@
1
+ Metadata-Version: 2.5
2
+ Name: mantos
3
+ Version: 0.1.0
4
+ Summary: The Mantos CLI — reach your Mantos tenant's API from a terminal
5
+ Project-URL: Homepage, https://mantos.cloud
6
+ Author: Systematic Labs LLC
7
+ License-Expression: LicenseRef-Proprietary
8
+ Keywords: agents,api,cli,mantos
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Environment :: Console
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: Other/Proprietary License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Topic :: Utilities
18
+ Requires-Python: >=3.11
19
+ Requires-Dist: click>=8.2
20
+ Requires-Dist: httpx>=0.25
21
+ Description-Content-Type: text/markdown
22
+
23
+ # mantos
24
+
25
+ The command-line client for [Mantos](https://mantos.cloud) — reach your tenant's
26
+ API from a terminal, a CI job, a container, or an agent session.
27
+
28
+ ```bash
29
+ pipx install mantos # or: pip install mantos
30
+ ```
31
+
32
+ ## One environment variable
33
+
34
+ A Mantos API key carries its own tenant slug, so the key is the whole
35
+ configuration:
36
+
37
+ ```bash
38
+ export MANTOS_API_KEY=mtk_<tenant>_<keyid>_<secret>
39
+
40
+ mantos api GET api/tenant/v1/envs/dev/agents
41
+ ```
42
+
43
+ There is nothing else to set — no host, no tenant, no profile. Mint a key in
44
+ the Mantos console (**Settings → API keys**); the secret is shown once, at mint,
45
+ and is not recoverable afterwards.
46
+
47
+ ## Commands
48
+
49
+ ```
50
+ mantos api METHOD PATH [--field K=V] [--raw-field K=V] [--json] [--timeout S]
51
+ mantos config set-host HOST
52
+ mantos config show
53
+ ```
54
+
55
+ `mantos api` reaches any tenant API path directly. `PATH` includes any query
56
+ string, and a leading slash is optional — on Git Bash, omitting it avoids the
57
+ shell rewriting the argument into a Windows filesystem path before the CLI sees
58
+ it.
59
+
60
+ `--field K=V` builds a JSON body, parsing `V` as JSON when it parses and sending
61
+ it as a string when it does not; `--raw-field` always sends a string. Neither is
62
+ accepted on `GET` or `HEAD`, where the API takes no body — silently dropping a
63
+ field would let you believe a filter was applied that never was.
64
+
65
+ ## Output, so a parser and a person can both read it
66
+
67
+ The response body is the only thing written to **stdout**. The status line for
68
+ a failure goes to **stderr**. Pipe stdout straight into `jq` without stripping
69
+ anything, and still see why a call went red.
70
+
71
+ ## Exit codes
72
+
73
+ | Code | Meaning |
74
+ |------|---------|
75
+ | `0` | The request succeeded (2xx). |
76
+ | `1` | The request was made and did not succeed — any non-2xx other than 401, plus a transport failure. |
77
+ | `2` | The invocation was wrong, or `MANTOS_API_KEY` is not set. Nothing was sent. |
78
+ | `3` | The credential was not accepted (401). |
79
+
80
+ A **403 is `1`, not `3`**. Authenticated-but-refused is a different fact from
81
+ credential-rejected: a key whose grants are narrower than its owner's authority
82
+ is *supposed* to be refused inside a scope it only partly holds, and that is the
83
+ authorization gate working rather than a broken key.
84
+
85
+ ## Host resolution
86
+
87
+ `MANTOS_HOST` › the tenant named by the key › a host stored with
88
+ `mantos config set-host`.
89
+
90
+ The environment variable wins so a support session, a smoke test, or a
91
+ one-off against another deployment needs no stored state and leaves none behind.
92
+ A stored host is the last resort precisely because it is invisible: a pin left
93
+ behind by an earlier session must not silently outrank the credential in front
94
+ of it.
95
+
96
+ ---
97
+
98
+ Mantos is a product of Systematic Labs LLC. This client talks to a deployed
99
+ Mantos tenant over HTTPS and contains no server code.
mantos-0.1.0/README.md ADDED
@@ -0,0 +1,77 @@
1
+ # mantos
2
+
3
+ The command-line client for [Mantos](https://mantos.cloud) — reach your tenant's
4
+ API from a terminal, a CI job, a container, or an agent session.
5
+
6
+ ```bash
7
+ pipx install mantos # or: pip install mantos
8
+ ```
9
+
10
+ ## One environment variable
11
+
12
+ A Mantos API key carries its own tenant slug, so the key is the whole
13
+ configuration:
14
+
15
+ ```bash
16
+ export MANTOS_API_KEY=mtk_<tenant>_<keyid>_<secret>
17
+
18
+ mantos api GET api/tenant/v1/envs/dev/agents
19
+ ```
20
+
21
+ There is nothing else to set — no host, no tenant, no profile. Mint a key in
22
+ the Mantos console (**Settings → API keys**); the secret is shown once, at mint,
23
+ and is not recoverable afterwards.
24
+
25
+ ## Commands
26
+
27
+ ```
28
+ mantos api METHOD PATH [--field K=V] [--raw-field K=V] [--json] [--timeout S]
29
+ mantos config set-host HOST
30
+ mantos config show
31
+ ```
32
+
33
+ `mantos api` reaches any tenant API path directly. `PATH` includes any query
34
+ string, and a leading slash is optional — on Git Bash, omitting it avoids the
35
+ shell rewriting the argument into a Windows filesystem path before the CLI sees
36
+ it.
37
+
38
+ `--field K=V` builds a JSON body, parsing `V` as JSON when it parses and sending
39
+ it as a string when it does not; `--raw-field` always sends a string. Neither is
40
+ accepted on `GET` or `HEAD`, where the API takes no body — silently dropping a
41
+ field would let you believe a filter was applied that never was.
42
+
43
+ ## Output, so a parser and a person can both read it
44
+
45
+ The response body is the only thing written to **stdout**. The status line for
46
+ a failure goes to **stderr**. Pipe stdout straight into `jq` without stripping
47
+ anything, and still see why a call went red.
48
+
49
+ ## Exit codes
50
+
51
+ | Code | Meaning |
52
+ |------|---------|
53
+ | `0` | The request succeeded (2xx). |
54
+ | `1` | The request was made and did not succeed — any non-2xx other than 401, plus a transport failure. |
55
+ | `2` | The invocation was wrong, or `MANTOS_API_KEY` is not set. Nothing was sent. |
56
+ | `3` | The credential was not accepted (401). |
57
+
58
+ A **403 is `1`, not `3`**. Authenticated-but-refused is a different fact from
59
+ credential-rejected: a key whose grants are narrower than its owner's authority
60
+ is *supposed* to be refused inside a scope it only partly holds, and that is the
61
+ authorization gate working rather than a broken key.
62
+
63
+ ## Host resolution
64
+
65
+ `MANTOS_HOST` › the tenant named by the key › a host stored with
66
+ `mantos config set-host`.
67
+
68
+ The environment variable wins so a support session, a smoke test, or a
69
+ one-off against another deployment needs no stored state and leaves none behind.
70
+ A stored host is the last resort precisely because it is invisible: a pin left
71
+ behind by an earlier session must not silently outrank the credential in front
72
+ of it.
73
+
74
+ ---
75
+
76
+ Mantos is a product of Systematic Labs LLC. This client talks to a deployed
77
+ Mantos tenant over HTTPS and contains no server code.
@@ -0,0 +1,107 @@
1
+ # The `mantos` CLI — its own distribution, and the reason this directory exists.
2
+ #
3
+ # 🔴 **Why the source MOVED rather than getting a pyproject alongside it.**
4
+ # Hatchling refuses any package path outside the project root. Measured, not
5
+ # assumed: `packages = ["../src/mantos_cli"]` fails the build with
6
+ # `Path #1 in field 'tool.hatch.build.only-include' must be relative`. A second
7
+ # distribution therefore needs a second project root with its sources *under*
8
+ # it, which is why `src/mantos_cli/` became `cli/src/mantos_cli/`. No build
9
+ # backend we would want takes the parent-relative shortcut — setuptools tolerates
10
+ # it for a wheel and then breaks sdists and editable installs, which is a worse
11
+ # place to discover the same limit.
12
+ #
13
+ # 🔴 **The distribution name `mantos` is the CLIENT** — the thing a tenant
14
+ # installs gets the guessable name. The server distribution is `mantos-server`
15
+ # (repo root), and it was renamed *for this*: two distributions sharing a name
16
+ # means `pip install -e ./cli` in a venv holding the editable server install
17
+ # silently uninstalls the server, leaving `import mantos` resolving to nothing
18
+ # while every CLI command still works. The root pyproject carries the detail.
19
+ #
20
+ # The PACKAGE names never collided and still do not: `mantos` (server) and
21
+ # `mantos_cli` (this). Only the distribution names did.
22
+ [project]
23
+ name = "mantos"
24
+ dynamic = ["version"]
25
+ description = "The Mantos CLI — reach your Mantos tenant's API from a terminal"
26
+ readme = "README.md"
27
+ requires-python = ">=3.11"
28
+ license = "LicenseRef-Proprietary"
29
+ authors = [{ name = "Systematic Labs LLC" }]
30
+ keywords = ["mantos", "cli", "agents", "api"]
31
+ classifiers = [
32
+ "Development Status :: 3 - Alpha",
33
+ "Environment :: Console",
34
+ "Intended Audience :: Developers",
35
+ "License :: Other/Proprietary License",
36
+ "Programming Language :: Python :: 3",
37
+ "Programming Language :: Python :: 3.11",
38
+ "Programming Language :: Python :: 3.12",
39
+ "Programming Language :: Python :: 3.13",
40
+ "Topic :: Utilities",
41
+ ]
42
+
43
+ # The CLI's whole runtime dependency set, and it is meant to stay this short —
44
+ # a client a tenant installs onto a laptop, a CI runner or an agent session
45
+ # should not drag a stack behind it.
46
+ #
47
+ # 🔴 The click floor is >=8.2 for a behavioural reason, not a feature one:
48
+ # `tests/cli` asserts the response body lands on stdout and the failure line on
49
+ # stderr, which is what lets an agent pipe stdout straight into a parser.
50
+ # Click 8.1's `CliRunner` merges the two and `result.stderr` raises, so a
51
+ # resolver that picked 8.1 would fail those tests in a way that reads like a CLI
52
+ # defect rather than a pin.
53
+ #
54
+ # `tests/cli/test_packaging.py` asserts this list actually covers every
55
+ # third-party module `mantos_cli` imports — declaring one and importing two is
56
+ # invisible in a dev venv, where the server distribution has already installed
57
+ # everything.
58
+ dependencies = [
59
+ "click>=8.2",
60
+ "httpx>=0.25",
61
+ ]
62
+
63
+ [project.urls]
64
+ Homepage = "https://mantos.cloud"
65
+
66
+ # The command name is `mantos` and it is independent of the distribution name —
67
+ # `httpie` installs `http`. Both happen to coincide here; the settled decision
68
+ # is the *command*, recorded in specifications/handoff-programmatic-access.md.
69
+ #
70
+ # This is also the line that could not exist in the root pyproject: a console
71
+ # script in the SERVER wheel pointing at `mantos_cli` would install a command
72
+ # that only fails when someone runs it, on a deployed image, during an incident.
73
+ # `tests/cli/test_packaging.py` still asserts the root declares no such script.
74
+ [project.scripts]
75
+ mantos = "mantos_cli.cli:main"
76
+
77
+ [build-system]
78
+ # >=1.27 for PEP 639 license expressions (`license = "LicenseRef-…"`). The root
79
+ # distribution's floor is >=1.21 and does not need raising for that.
80
+ requires = ["hatchling>=1.27"]
81
+ build-backend = "hatchling.build"
82
+
83
+ # One source of truth for the version: the literal in the package. The CLI
84
+ # deliberately does NOT read `mantos.__version__` — that import would cross the
85
+ # very boundary that makes this distribution separable (`.importlinter` contract
86
+ # `cli-independent-of-server`), so the two version literals are independent by
87
+ # design and are allowed to diverge.
88
+ [tool.hatch.version]
89
+ path = "src/mantos_cli/__init__.py"
90
+
91
+ [tool.hatch.build.targets.wheel]
92
+ packages = ["src/mantos_cli"]
93
+
94
+ [tool.hatch.build.targets.sdist]
95
+ # An explicit list rather than hatchling's default sweep of the project root:
96
+ # the default would ship whatever else ends up in this directory (a `dist/`, a
97
+ # stray venv) into the artifact that gets uploaded to PyPI.
98
+ include = ["src/mantos_cli", "README.md"]
99
+ # ⚠️ `include` does NOT bound the sdist on its own. Hatchling force-includes the
100
+ # `.gitignore` it used for exclusions, and with none in this directory it walked
101
+ # up and shipped the REPO ROOT's — publishing our internal path layout inside a
102
+ # public artifact. `exclude = [".gitignore"]` does not stop it (measured). The
103
+ # fix is the local `cli/.gitignore`, which is why that two-line file exists and
104
+ # must not be deleted as redundant with the root one.
105
+ #
106
+ # Read the built tarball rather than trusting this block —
107
+ # `tests/cli/test_packaging.py` does exactly that.
@@ -0,0 +1,26 @@
1
+ """The ``mantos`` CLI — a client for the Mantos tenant REST API.
2
+
3
+ 🔴 **This package is its own distribution, not part of the server wheel.** Same
4
+ precedent, and the same reason, as ``sandbox_runner`` and ``egress_authz``: a
5
+ tenant should not install the control plane to get a client. Since P4d that is
6
+ structural rather than an exclusion — the package lives under ``cli/``, which
7
+ has its own ``pyproject.toml`` (published as ``mantos``, against the server's
8
+ ``mantos-server``). ``tests/cli/test_packaging.py`` asserts it against both
9
+ built artifacts rather than trusting this comment.
10
+
11
+ The corollary is the import boundary: **``mantos_cli`` must never import
12
+ ``mantos``.** It talks to the deployed control plane over HTTP and knows
13
+ nothing of its internals — that is what makes it separable at all. The
14
+ ``.importlinter`` contract ``cli-independent-of-server`` enforces it, because
15
+ one ``from mantos.control...`` import would undo the separation silently and
16
+ still pass every test.
17
+
18
+ Version is a standalone literal for the same reason: reading
19
+ ``mantos.__version__`` would be an import across that boundary.
20
+ """
21
+
22
+ from __future__ import annotations
23
+
24
+ __version__ = "0.1.0"
25
+
26
+ __all__ = ["__version__"]
@@ -0,0 +1,20 @@
1
+ """``python -m mantos_cli`` entry point.
2
+
3
+ ⚠️ **This module holds nothing but the call.** ``python -m pkg`` imports the
4
+ module a *second* time under the name ``__main__``, so anything defined here —
5
+ a class, an exception, a sentinel — exists twice under two identities, and
6
+ ``except`` clauses silently stop matching (memory
7
+ ``reference_dash_m_double_import``; #2380). Keeping the file to one import and
8
+ one call makes that unrepresentable.
9
+
10
+ A tenant runs ``mantos``, not this: the console script ships with the CLI's own
11
+ distribution (``cli/pyproject.toml``, P4d). This module stays because
12
+ ``python -m mantos_cli`` is what works from a source checkout, before anything
13
+ is installed.
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ from mantos_cli.cli import main
19
+
20
+ raise SystemExit(main())