healthcloud-cli 3.1.0__tar.gz → 3.2.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 (27) hide show
  1. healthcloud_cli-3.2.0/.gitignore +257 -0
  2. healthcloud_cli-3.2.0/PKG-INFO +405 -0
  3. healthcloud_cli-3.2.0/README.md +387 -0
  4. {healthcloud_cli-3.1.0 → healthcloud_cli-3.2.0}/healthcloud_cli/__init__.py +0 -1
  5. healthcloud_cli-3.2.0/healthcloud_cli/ams/__init__.py +1 -0
  6. healthcloud_cli-3.2.0/healthcloud_cli/ams/auth.py +49 -0
  7. healthcloud_cli-3.2.0/healthcloud_cli/ams/commands.py +242 -0
  8. healthcloud_cli-3.2.0/healthcloud_cli/ams/output.py +70 -0
  9. healthcloud_cli-3.2.0/healthcloud_cli/ams/target.py +117 -0
  10. healthcloud_cli-3.2.0/healthcloud_cli/ams/tuning.py +247 -0
  11. healthcloud_cli-3.2.0/healthcloud_cli/ams/ui.py +54 -0
  12. {healthcloud_cli-3.1.0 → healthcloud_cli-3.2.0}/healthcloud_cli/cli.py +45 -18
  13. {healthcloud_cli-3.1.0 → healthcloud_cli-3.2.0}/healthcloud_cli/context.py +9 -9
  14. {healthcloud_cli-3.1.0 → healthcloud_cli-3.2.0}/healthcloud_cli/contracts/mcp-tools.manifest.json +682 -61
  15. {healthcloud_cli-3.1.0 → healthcloud_cli-3.2.0}/healthcloud_cli/manifest.py +9 -5
  16. {healthcloud_cli-3.1.0 → healthcloud_cli-3.2.0}/healthcloud_cli/output.py +2 -1
  17. {healthcloud_cli-3.1.0 → healthcloud_cli-3.2.0}/healthcloud_cli/params.py +4 -8
  18. {healthcloud_cli-3.1.0 → healthcloud_cli-3.2.0}/pyproject.toml +9 -4
  19. healthcloud_cli-3.1.0/.gitignore +0 -110
  20. healthcloud_cli-3.1.0/PKG-INFO +0 -242
  21. healthcloud_cli-3.1.0/README.md +0 -227
  22. {healthcloud_cli-3.1.0 → healthcloud_cli-3.2.0}/hatch_build.py +0 -0
  23. {healthcloud_cli-3.1.0 → healthcloud_cli-3.2.0}/healthcloud_cli/contracts/__init__.py +0 -0
  24. {healthcloud_cli-3.1.0 → healthcloud_cli-3.2.0}/healthcloud_cli/main.py +0 -0
  25. {healthcloud_cli-3.1.0 → healthcloud_cli-3.2.0}/healthcloud_cli/util.py +0 -0
  26. {healthcloud_cli-3.1.0 → healthcloud_cli-3.2.0}/scripts/__init__.py +0 -0
  27. {healthcloud_cli-3.1.0 → healthcloud_cli-3.2.0}/scripts/bundle_manifest.py +0 -0
@@ -0,0 +1,257 @@
1
+ tests/integration/artifacts/
2
+ test-artifacts/
3
+
4
+ # ── Python ────────────────────────────────────────────────────────────────────
5
+ __pycache__/
6
+ *.py[cod]
7
+ *$py.class
8
+ *.pyo
9
+ *.pyd
10
+ *.pyc
11
+
12
+ # Distribution / packaging
13
+ dist/
14
+ build/
15
+ *.egg-info/
16
+ *.egg
17
+ .eggs/
18
+ wheels/
19
+ MANIFEST
20
+
21
+ # Virtual environments
22
+ .venv/
23
+ venv/
24
+ env/
25
+ .env/
26
+ ENV/
27
+ env.bak/
28
+ venv.bak/
29
+
30
+ # Installer logs
31
+ pip-log.txt
32
+ pip-delete-this-directory.txt
33
+
34
+ # ── Testing ───────────────────────────────────────────────────────────────────
35
+ .pytest_cache/
36
+ .coverage
37
+ .coverage.*
38
+ coverage.xml
39
+ htmlcov/
40
+ *.cover
41
+ *.tox/
42
+ nosetests.xml
43
+ test-results/
44
+ junit.xml
45
+
46
+ # ── Type checking ─────────────────────────────────────────────────────────────
47
+ .mypy_cache/
48
+ .dmypy.json
49
+ dmypy.json
50
+ .pytype/
51
+ .pyre/
52
+
53
+ # ── Secrets (never commit) ────────────────────────────────────────────────────
54
+ gcp-key.json
55
+ *.key.json
56
+
57
+ # ── IDEs ──────────────────────────────────────────────────────────────────────
58
+ .vscode/
59
+ .idea/
60
+ *.iml
61
+ *.iws
62
+ *.ipr
63
+ .project
64
+ .classpath
65
+ .settings/
66
+ *.swp
67
+ *.swo
68
+ *~
69
+
70
+ # ── macOS ─────────────────────────────────────────────────────────────────────
71
+ .DS_Store
72
+ .AppleDouble
73
+ .LSOverride
74
+ ._*
75
+ .Spotlight-V100
76
+ .Trashes
77
+ Icon
78
+
79
+ # ── Environment / secrets ─────────────────────────────────────────────────────
80
+ .env
81
+ .env.*
82
+ !.env.example
83
+ !.env.template
84
+ *.pem
85
+ *.key
86
+ *.p12
87
+ *.pfx
88
+ secrets/
89
+ !docs/secrets/expected-schema.json
90
+ credentials/
91
+ service-account*.json
92
+ *-service-account.json
93
+ gcp-key.json
94
+ sa-key.json
95
+
96
+ # ── AWS ───────────────────────────────────────────────────────────────────────
97
+ .aws/
98
+ samconfig.toml
99
+ packaged*.yaml
100
+ packaged*.json
101
+ .aws-sam/
102
+
103
+ # Contract baked into the Lambda package at deploy time (see the "Bundle hc
104
+ # shared library" step in .github/workflows/_deploy-api.yml). Build output —
105
+ # the source of truth stays contracts/generated/<service>/openapi.json.
106
+ hc/contracts/_generated/
107
+
108
+ # ── Terraform / CDK ───────────────────────────────────────────────────────────
109
+ .terraform/
110
+ *.tfstate
111
+ *.tfstate.*
112
+ *.tfplan
113
+ cdk.out/
114
+ cdk.context.json
115
+
116
+ # ── Docker ────────────────────────────────────────────────────────────────────
117
+ *.dockerignore
118
+
119
+ # ── Node (if any tooling) ─────────────────────────────────────────────────────
120
+ node_modules/
121
+ npm-debug.log*
122
+ yarn-debug.log*
123
+ yarn-error.log*
124
+ .npm/
125
+ .yarn/
126
+
127
+ # ── Logs ──────────────────────────────────────────────────────────────────────
128
+ *.log
129
+ logs/
130
+ *.out
131
+
132
+ # ── Reports ───────────────────────────────────────────────────────────────────
133
+ reports/
134
+ *.report.json
135
+ *.report.html
136
+
137
+ # ── Temporary files ───────────────────────────────────────────────────────────
138
+ *.tmp
139
+ *.temp
140
+ *.bak
141
+ *.orig
142
+ *.rej
143
+ tmp/
144
+ temp/
145
+
146
+ # Imported SDK build and documentation outputs
147
+ # Logs
148
+ logs/
149
+ *.log
150
+ npm-debug.log*
151
+ yarn-debug.log*
152
+ yarn-error.log*
153
+ pnpm-debug.log*
154
+
155
+ # Environment files
156
+ **/live-state.json
157
+
158
+ # Node / npm
159
+ node_modules/
160
+ .npm/
161
+ .pnpm-store/
162
+ dist/
163
+ build/
164
+
165
+ # packages/cli/npm bundles the manifest from packages/cli/contracts at build/
166
+ # test time (scripts/copy-manifest.cjs) — that copy is generated, not source.
167
+ packages/cli/npm/contracts/
168
+ coverage/
169
+ report/
170
+ *.tsbuildinfo
171
+
172
+ # Python / pip
173
+ __pycache__/
174
+ *.py[cod]
175
+ *.pyo
176
+ .Python
177
+ .venv/
178
+ venv/
179
+ env/
180
+ pip-wheel-metadata/
181
+ *.egg-info/
182
+ .pytest_cache/
183
+ .mypy_cache/
184
+ .ruff_cache/
185
+ htmlcov/
186
+
187
+ # Java / Maven
188
+ target/
189
+ .mvn/timing.properties
190
+ .mvn/wrapper/maven-wrapper.jar
191
+ *.class
192
+ *.jar
193
+ *.war
194
+ *.ear
195
+
196
+ # .NET / NuGet
197
+ # Scoped to packages/nuget/ specifically — an unscoped `bin/`/`obj/` matches
198
+ # a directory of that name at ANY depth (gitignore has no implicit anchor),
199
+ # which silently swallowed the real source file packages/cli/npm/src/bin/hc.ts
200
+ # and broke that package's CI build (the file was never committed).
201
+ packages/nuget/**/bin/
202
+ packages/nuget/**/obj/
203
+ TestResults/
204
+ *.nupkg
205
+ *.snupkg
206
+ *.user
207
+ *.suo
208
+
209
+ # IDEs and editors
210
+ .idea/
211
+ .vscode/
212
+ *.swp
213
+ *.swo
214
+ .DS_Store
215
+ Thumbs.db
216
+
217
+ # Build outputs and caches
218
+ out/
219
+ tmp/
220
+ temp/
221
+ .cache/
222
+ .codegraph/
223
+ .parcel-cache/
224
+ .turbo/
225
+
226
+ # Disposable OpenAPI Generator staging and C#/Java sanity outputs
227
+ .generated/
228
+
229
+ # Rendered documentation, immutable S3 release snapshots, and the latest
230
+ # pointer are build/publish artifacts generated on demand. Versioned inputs
231
+ # remain the source of truth in this repository.
232
+ docs-data/v1/
233
+ docs-data/releases/
234
+ docs-data/latest.json
235
+
236
+ # ── Generated documentation ──────────────────────────────────────────────
237
+ # The pip packages force-include docs/ (hatchling errors outright if it is
238
+ # absent), so those two keep a .gitkeep and are populated by docs:build.
239
+ #
240
+ # Built by `npm run docs:build` from contracts/pinned + the SDK source, and
241
+ # published to S3 by .github/workflows/docs-publish.yml. The package publish
242
+ # workflows regenerate packages/*/docs before packaging, because the package
243
+ # manifests ship it. None of it is source -- do not commit it.
244
+ packages/npm/docs/
245
+ packages/pip/docs/*
246
+ !packages/pip/docs/.gitkeep
247
+ packages/npm-tenantadmin/docs/
248
+ packages/npm-ams/docs/
249
+ packages/pip-tenantadmin/docs/*
250
+ !packages/pip-tenantadmin/docs/.gitkeep
251
+ packages/npm/README.md
252
+ packages/pip/README.md
253
+ packages/npm-tenantadmin/README.md
254
+ packages/pip-tenantadmin/README.md
255
+
256
+ # Live SDK test assets stay in the archived SDK history, outside this source import.
257
+ integration-tests/shared/test-assets/
@@ -0,0 +1,405 @@
1
+ Metadata-Version: 2.5
2
+ Name: healthcloud-cli
3
+ Version: 3.2.0
4
+ Summary: Command-line interface for the HealthCloud MCP gateway, generated from the shared MCP tool manifest.
5
+ Project-URL: Issues, https://github.com/healthcloudservices/healthcloud-services/issues
6
+ Project-URL: Repository, https://github.com/healthcloudservices/healthcloud-services
7
+ Author: Healthcheck Systems Inc
8
+ License-Expression: MIT
9
+ Keywords: cli,health-cloud,healthcare,healthcloud,mcp
10
+ Requires-Python: >=3.14
11
+ Requires-Dist: click>=8.1
12
+ Requires-Dist: healthcloud-sdk>=0.9.0
13
+ Requires-Dist: healthcloud-tenantadmin>=1.1.1
14
+ Provides-Extra: dev
15
+ Requires-Dist: pytest>=9.0.3; extra == 'dev'
16
+ Requires-Dist: respx>=0.21; extra == 'dev'
17
+ Description-Content-Type: text/markdown
18
+
19
+ # healthcloud-cli
20
+
21
+ Requires **Python 3.14 or newer**.
22
+
23
+ `hc` provides the HealthCloud MCP gateway and bounded deployed AMS administration.
24
+ The `hc mcp` subtree has exactly one subcommand per
25
+ MCP tool -- generated dynamically at startup from a shared manifest across
26
+ audiences such as `patient`, `fieldagent`, `ehr`, `vitals`, `diagnostics`,
27
+ `appointments`, `graph`, `person`, `provider`, `tenantadmin`, `connectors`,
28
+ and `telehealth`. Run `hc mcp tools list` to see the exact, current set for
29
+ your installed version. Nothing here is hand-written per tool: the same
30
+ manifest also drives the sibling NPM CLI (`@healthcloud CLI` in
31
+ `packages/cli/npm`), so command names match exactly between the two.
32
+
33
+ ## Install
34
+
35
+ ```bash
36
+ pip install healthcloud-cli
37
+ ```
38
+
39
+ This installs the `hc` console script plus its dependency, the
40
+ [`healthcloud-sdk`](../../pip) package, which does the actual HTTP/JSON-RPC
41
+ work against the MCP gateway.
42
+
43
+ ## Local development
44
+
45
+ Use uv 0.12.5 and Python 3.14. The package's uv source override installs the
46
+ SDK checkout in editable mode; its committed lock includes the test and build
47
+ tools. Released package consumers can still use pip.
48
+
49
+ ```bash
50
+ cd packages/cli/pip
51
+ uv lock --check
52
+ uv sync --frozen --extra dev
53
+ uv run --frozen --extra dev python -m pytest
54
+ uv run --frozen hc --help
55
+ uv run --frozen hc mcp tools list --audience patient
56
+ uv run --frozen hc mcp patient get-patient --help
57
+ ```
58
+
59
+ The bundled tool manifest (`healthcloud_cli/contracts/mcp-tools.manifest.json`)
60
+ is a copy of `packages/cli/contracts/mcp-tools.manifest.json`. Re-sync it
61
+ after pulling manifest changes with:
62
+
63
+ ```bash
64
+ python scripts/bundle_manifest.py
65
+ ```
66
+
67
+ This also runs automatically as a hatchling build hook whenever you `python
68
+ -m build`, so a built wheel/sdist is always self-contained and never depends
69
+ on a relative path outside the installed package.
70
+
71
+ ## Authentication & configuration
72
+
73
+ Every command accepts these global options (place them before the `mcp`
74
+ subcommand):
75
+
76
+ | Flag | Env var | Meaning |
77
+ |-------------------|--------------------|-----------------------------------------------|
78
+ | `--access-token` | `HC_ACCESS_TOKEN` | Bearer token sent to the MCP gateway |
79
+ | `--base-url` | `HC_MCP_BASE_URL` | Override the MCP gateway base URL |
80
+ | `--profile` | `HC_PROFILE` | Named profile (see below) |
81
+ | `--output` | -- | `pretty` (default) \| `json` \| `raw` |
82
+ | `--raw` | -- | Shortcut for `--output raw` |
83
+ | `--verbose` | -- | Print request diagnostics to stderr |
84
+
85
+ Precedence, highest wins: **explicit CLI flag > environment variable >
86
+ profile file value > built-in default** (`environment` defaults to `"dev"`;
87
+ `accessToken`/`baseUrl` default to unset). The resolved access token is never
88
+ written to logs, generated files, or test snapshots.
89
+
90
+ ### Optional profile file
91
+
92
+ `~/.healthcloud/cli/profiles.json`:
93
+
94
+ ```json
95
+ {
96
+ "dev-mia": {
97
+ "baseUrl": "https://dev-api-mcp.health.cloud",
98
+ "accessToken": "eyJ...",
99
+ "environment": "dev"
100
+ }
101
+ }
102
+ ```
103
+
104
+ A missing profiles file is not an error -- profiles are entirely optional. If
105
+ `--profile`/`HC_PROFILE` names a profile and the file (or that entry) is
106
+ missing, `hc` exits with a clear usage error rather than silently ignoring
107
+ it.
108
+
109
+ ```bash
110
+ # get-patient is self-service — the patient is resolved from the access
111
+ # token, so no --patient-id flag exists.
112
+ hc --profile dev-mia mcp patient get-patient
113
+ ```
114
+
115
+ ## Listing and inspecting tools
116
+
117
+ ```bash
118
+ # Local (bundled manifest, no network call)
119
+ hc mcp tools list
120
+ hc mcp tools list --audience patient
121
+
122
+ # Live gateway (requires --audience)
123
+ hc mcp tools list --audience patient --remote
124
+
125
+ # Full manifest entry for one tool (description, inputSchema, method/path)
126
+ hc mcp tools show patient add_insurance --output json
127
+ ```
128
+
129
+ ## Calling a tool
130
+
131
+ Every manifest tool is its own subcommand, grouped by audience:
132
+
133
+ ```bash
134
+ hc mcp patient get-patient
135
+ hc mcp appointments book-appointment --patient-id patient-123 --slot-id slot-456
136
+
137
+ # Every Diagnostics tool takes an explicit --patient-id — providers and
138
+ # field agents legitimately look up or record diagnostics for a patient
139
+ # other than themselves. When the caller holds a patient token, the backend
140
+ # enforces server-side that --patient-id must be their own (403 otherwise).
141
+ hc mcp diagnostics create-rapid-test --patient-id patient-123 --test-type covid-19 --result negative
142
+ ```
143
+
144
+ Run `--help` on any generated command to see its real manifest description
145
+ and arguments:
146
+
147
+ ```bash
148
+ hc mcp patient get-patient --help
149
+ ```
150
+
151
+ ### Argument flags
152
+
153
+ - **Primitive properties** (`string`/`number`/`integer`/`boolean`) become a
154
+ normal flag in kebab-case, e.g. `patient_id` -> `--patient-id`.
155
+ - `enum` values are validated; invalid values are rejected before any
156
+ network call.
157
+ - `minimum`/`maximum`/`exclusiveMinimum`/`exclusiveMaximum` are enforced
158
+ the same way.
159
+ - Boolean properties are a tri-state flag pair: `--flag/--no-flag`.
160
+ Passing neither leaves the value unset (falls back to the manifest
161
+ default or an `--input`/`--stdin` value, if any); passing one sets it
162
+ explicitly to `true`/`false`.
163
+ - **Object/array properties are never flattened.** They get a single
164
+ `--<prop>-json` flag that takes a raw JSON string, e.g.:
165
+
166
+ ```bash
167
+ # create-medication is self-service — no --patient-id flag; the patient is
168
+ # resolved server-side from the access token.
169
+ hc mcp patient create-medication \
170
+ --name "Metformin" \
171
+ --dosage-json '{"value":10,"unit":"mg","frequency":"once_daily"}'
172
+ ```
173
+ - Path parameters (from `{placeholders}` in the tool's HTTP path) are always
174
+ required, in addition to whatever `inputSchema.required` lists.
175
+
176
+ ### Bulk input: `--input` / `--stdin`
177
+
178
+ ```bash
179
+ hc mcp appointments book-appointment --input request.json
180
+ cat request.json | hc mcp appointments book-appointment --stdin
181
+ ```
182
+
183
+ `--input <file>` and `--stdin` both supply a *base* JSON object of
184
+ arguments. `--input` and `--stdin` cannot be combined. Merge precedence
185
+ (highest wins): **manifest defaults < `--input`/`--stdin` object < explicit
186
+ flags** -- i.e. an explicit flag you actually pass always overrides the same
187
+ key coming from a file or stdin, which in turn overrides the schema default.
188
+
189
+ After merging, the final object is validated against the tool's
190
+ `inputSchema` (required fields present, correct types, enum membership,
191
+ numeric bounds). Any validation failure prints a clear message to stderr and
192
+ exits **2**, without making a network call.
193
+
194
+ ### `hc mcp call` -- generic escape hatch
195
+
196
+ `hc mcp call` dispatches to any MCP tool by its exact snake_case tool name --
197
+ including one not yet present in the bundled manifest (the tool name itself
198
+ is never validated against the manifest, it's just forwarded):
199
+
200
+ ```bash
201
+ # get_patient is self-service and takes no arguments — {} is a complete,
202
+ # valid call.
203
+ hc mcp call patient get_patient --input '{}'
204
+ hc mcp call patient get_patient --input-file request.json
205
+ cat request.json | hc mcp call patient get_patient --stdin
206
+ ```
207
+
208
+ Note the deliberate inconsistency versus named commands: here `--input` takes
209
+ an inline JSON **value**, not a file path -- use `--input-file` for a file.
210
+ Exactly one of `--input` / `--input-file` / `--stdin` may be given (or none,
211
+ meaning `{}`).
212
+
213
+ ## Output modes
214
+
215
+ The MCP tool-call result is `{ content: [{type:"text", text: "..."}],
216
+ is_error: bool }` from the JSON-RPC response's `.result`, or the JSON-RPC
217
+ `.error` object if the gateway returned one.
218
+
219
+ - **`pretty`** (default): if `content[0].text` parses as JSON, pretty-prints
220
+ the parsed value; otherwise prints the raw text. On a JSON-RPC error,
221
+ prints `error.message` (and `error.code` with `--verbose`) to stderr.
222
+ - **`json`**: prints the tool result's parsed JSON (or raw text if
223
+ unparseable) to stdout, with no envelope.
224
+ - **`raw`**: prints the complete JSON-RPC envelope (`id`, `jsonrpc`,
225
+ `result`, `error`) as returned by the gateway.
226
+
227
+ Diagnostics and `--verbose` logs always go to stderr -- stdout stays
228
+ pipeable in every mode.
229
+
230
+ ## Exit codes
231
+
232
+ | Code | Meaning |
233
+ |------|-----------------------------------------------------------------------|
234
+ | `0` | Success |
235
+ | `2` | Local input validation failure (bad JSON, missing required field, invalid enum/number, `--input`+`--stdin` both given, unknown option) -- no network call made |
236
+ | `3` | HTTP/network failure talking to the MCP gateway |
237
+ | `4` | JSON-RPC error response (`.error` is not `None`) |
238
+ | `5` | MCP tool result reported `is_error: true` |
239
+
240
+ ## Building
241
+
242
+ ```bash
243
+ uv lock --check
244
+ uv run --frozen python -m build --no-isolation
245
+ uv run --frozen python -m zipfile -l dist/*.whl # confirm the bundled manifest is included
246
+ ```
247
+
248
+ ## Deployed AMS administration (source checkout)
249
+
250
+ The reviewed AMS administration SDK is not published yet. Use this checkout's
251
+ editable SDK and tenant-admin sources; no released SDK version is claimed to
252
+ contain `ams_admin`. An installed SDK missing that capability is refused before
253
+ login. Ordinary MCP commands keep their existing behavior.
254
+
255
+ Prepare ignored SDK build READMEs from tracked inputs, then install the locked
256
+ editable packages (the CLI README itself is tracked):
257
+
258
+ ```bash
259
+ node tooling/docs-compiler/prepare-package-readmes.mjs
260
+ cd packages/cli/pip
261
+ uv sync --frozen --extra dev
262
+ uv run --frozen hc ams --help
263
+ ```
264
+
265
+ Bootstrap candidate IDs with the public SDK discovery endpoint. Both flags are
266
+ required; no MCP defaults, admin login, or automatic candidate selection are used:
267
+
268
+ ```bash
269
+ uv run --frozen hc ams discover --environment dev --tenant-id TENANT_ID
270
+ ```
271
+
272
+ Every other command requires an explicit local, non-secret target JSON file.
273
+ Only the canonical HTTPS AMS origin for that environment is accepted; custom
274
+ origins require separately verified support. Target and nested qualification keys
275
+ are strict. Unknown/unavailable qualification may be represented by omitted
276
+ records or empty qualification `{}` for inspection/UI, but blocks planning.
277
+
278
+ The following is a **schema example**, not evidence of deployed CareCo eligibility.
279
+ Replace its assertions only after an operator has established the corresponding
280
+ proof. `deployed_build` and `proof_ref` are references, never credentials:
281
+
282
+ ```json
283
+ {
284
+ "schema_version": 1,
285
+ "environment": "dev",
286
+ "tenant_id": "TENANT_ID",
287
+ "agent_id": "EXPLICIT_SELECTED_AGENT_ID",
288
+ "api_origin": "https://dev-amsservices.health.cloud",
289
+ "qualification": {
290
+ "runtime": {"source": "OPERATOR_VERIFIED_RUNTIME", "proof_ref": "RUNTIME_PROOF"},
291
+ "instructions": {"source": "agent.instructions", "proof_ref": "INSTRUCTION_SOURCE_PROOF"},
292
+ "greetings": {"source": "agent.greetings", "proof_ref": "GREETING_SOURCE_PROOF"},
293
+ "backend_model_context": {
294
+ "deployed_build": "OPERATOR_VERIFIED_DEPLOYED_REVISION",
295
+ "config_version": 7,
296
+ "proof_ref": "FULL_INPUT_AND_WRITER_COVERAGE_REVIEW_PROOF",
297
+ "current_build_confirmed": true,
298
+ "fresh_session": true,
299
+ "no_attachments_or_history": true,
300
+ "full_inputs_approved": true,
301
+ "change_path_without_logs": true
302
+ }
303
+ }
304
+ }
305
+ ```
306
+
307
+ Qualification is an operator assertion with evidence, never authorization.
308
+ Server-side tenant-admin authorization remains mandatory. No current-build API is
309
+ established: the CLI cannot automatically detect an unreported deployment, verify
310
+ actual runtime consumption, attest deployed all-writer coverage, or audit model
311
+ inputs. A changed/unavailable build or agent configuration invalidates the review;
312
+ the operator must refresh the record. The recorded config version must equal the
313
+ inspected version before planning/apply/restore.
314
+ `full_inputs_approved` means an operator approved non-sensitive **full planner and
315
+ reviewer inputs**, including custom_tools, catalogs, all agent fields, and all other
316
+ server context. Output projection does not sanitize server-side model context.
317
+ `change_path_without_logs` requires evidence that the exact deterministic modify
318
+ request uses the change path, avoiding the direct-answer branch's recent logs.
319
+ Unknown effective sources and file-backed/ignored instructions block tuning.
320
+
321
+ Before `plan`, `apply` or selected-field `restore`, the operator must review evidence
322
+ that the actual serving build includes **all writer version coverage**: ordinary
323
+ agent updates and startup/migration repair writers advance `config_version`
324
+ atomically with their changes, and tuning apply uses transactional compare-and-set
325
+ against the expected version. Bind this coverage evidence and the full-input
326
+ review together in the existing `qualification.backend_model_context.proof_ref`
327
+ review bundle for its `deployed_build`, inspected `config_version` and
328
+ `current_build_confirmed` assertion. AMS source prerequisites
329
+ [#488](https://github.com/healthcloudservices/healthcloud-ams-services/pull/488) and
330
+ [#497](https://github.com/healthcloudservices/healthcloud-ams-services/pull/497)
331
+ are evidence leads; source tests, PR merges, or a numeric `config_version` alone
332
+ cannot prove coverage in the serving build. If deployed identity or any writer's
333
+ coverage is unknown, or a writer still bypasses version advancement, stop
334
+ `plan`/`apply`/`restore`; bounded read-only inspection/UI may continue under their
335
+ existing limits. Refresh this evidence after a changed/unknown build or agent
336
+ configuration and recheck it before apply and selected-field restore. This is an
337
+ operator prerequisite: the current CLI does not automatically attest deployment
338
+ or all-writer coverage, and the record adds no server authorization boundary.
339
+
340
+ Credentials enter only through `HC_AMS_ADMIN_EMAIL` and `HC_AMS_ADMIN_PASSWORD`
341
+ in the current process, intended for composition with the existing
342
+ `onepassword-env` wrapper. Each invocation logs in through `HCTenantAdminSDK`;
343
+ tokens remain private in memory. There is no token cache, fallback identity,
344
+ secret argument, resolved env file, or browser credential bridge. Root MCP
345
+ `--access-token`, `--base-url`, their environment equivalents, and token/base-URL
346
+ profiles are refused for AMS. Root profile environment values do not select AMS.
347
+
348
+ ```bash
349
+ uv run --frozen hc ams --target-file TARGET.json inspect
350
+ uv run --frozen hc ams --target-file TARGET.json inspect --out PRIVATE_INSPECTION.json
351
+ uv run --frozen hc ams --target-file TARGET.json plan --changes-file PRIVATE_CHANGES.json --out PRIVATE_RECEIPT.json
352
+ uv run --frozen hc ams --target-file TARGET.json show --receipt PRIVATE_RECEIPT.json --out PRIVATE_DIFF.json
353
+ uv run --frozen hc ams --target-file TARGET.json apply --receipt PRIVATE_RECEIPT.json --confirm-plan-hash DISPLAYED_HASH
354
+ uv run --frozen hc ams --target-file TARGET.json restore --receipt PRIVATE_RECEIPT.json --out PRIVATE_RESTORE_RECEIPT.json
355
+ uv run --frozen hc ams --target-file TARGET.json ui --repo EXISTING_AMS_WORKTREE
356
+ ```
357
+
358
+ Changes JSON accepts only nonempty subsets of `instructions` (string) and
359
+ `greetings` (language-key to string map). Input changes/receipts must be regular,
360
+ owner-only files (for example create under `umask 077`). Outputs use exclusive
361
+ 0600 creation and refuse overwrite/symlinks; failed operations remove unfinished
362
+ outputs. No whole-agent snapshot is saved. Free text appears only in explicitly
363
+ requested private files for human review before any AI use. Default output in
364
+ pretty/json/verbose modes contains bounded metadata and hashes; AMS refuses raw.
365
+
366
+ The planner receives `Update the agent configuration to exactly these field
367
+ values: ` followed by sorted, compact requested JSON. Extra fields, files,
368
+ validation errors, warnings/skipped references, blocking or unknown review
369
+ findings, and approximate wording are refused. Each immutable field change must
370
+ include `before` and exact `after` values so a modified receipt cannot redefine a
371
+ restore. A server plan omitting `before` cannot safely support this workflow;
372
+ review/replan rather than synthesizing server provenance. `show`/`apply` reload the
373
+ immutable backend plan/hash. Before apply, recheck the deployed coverage and
374
+ full-input qualification above. Apply requires the displayed hash, matching
375
+ version and selected before-values, and sends `confirm=True` once. HTTP 401/403
376
+ and 409 never trigger identity fallback or mutation replay.
377
+
378
+ On transport failure, apply records an unknown outcome and reconciles through GET
379
+ plan/agent without retrying the mutation. Confirmed saves require applied status,
380
+ selected-field readback and exactly the next config version. The current public
381
+ response omits publication_status: **saved/readback confirmed is reported separately
382
+ from publication unknown and runtime unverified**, with nonzero exit status for
383
+ complete success. `publish_failed` is reported separately. Do not replay a saved
384
+ apply to resolve publication. A fresh invocation refuses an already consumed plan.
385
+
386
+ Restore creates a new reviewed plan from only the selected fields' authoritative
387
+ before-values against the latest config version. Unrelated edits are preserved;
388
+ a current same-field mismatch blocks restore. There is no force restore. Refresh
389
+ operator qualification, including deployed all-writer coverage and full-input
390
+ evidence, for the latest build/version first, then review the new
391
+ restore receipt with `show` and confirm its new hash with `apply`.
392
+
393
+ UI launch validates the existing `test-client-ui/package.json` Vite script,
394
+ refuses lifecycle hooks, and invokes `npm run dev -- --host 127.0.0.1` by argv
395
+ with `shell=False`. It installs nothing and launches no backend. The allowlisted
396
+ child environment includes toolchain essentials plus only these public target
397
+ variables: `VITE_API_URL`, `VITE_HEALTHCLOUD_ENVIRONMENT`, `VITE_TUNING_TENANT_ID`,
398
+ `VITE_TUNING_AGENT_ID`. Injected HC/OP credentials and other VITE/NODE/NPM options
399
+ are excluded. It prints `/app/agents/{agent_id}`; browser login remains separate.
400
+ The supplied existing worktree and its local frontend configuration remain
401
+ operator-controlled.
402
+
403
+ AMS failures exit nonzero with safe categories, never backend exception bodies.
404
+ In particular, apply may exit nonzero after a confirmed save because publication
405
+ is unknown: inspect the emitted outcome before any next action.