@steve228uk/nhs-cli 0.0.1 → 0.1.0

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,27 @@
1
+ # Architecture
2
+
3
+ The modern entrypoint and legacy wrapper share one implementation.
4
+
5
+ | Module | Responsibility |
6
+ | --- | --- |
7
+ | `cli` | Parsing, validation, lock ownership, composition and exports |
8
+ | `domains` | Capabilities, read adapters, prescription scope and response checks |
9
+ | `auth` | Sessions, OAuth validation, login, GP uplift and bearer renewal |
10
+ | `transport` | HTTPS policy, scoped cookies, redirects, deadlines and body limits |
11
+ | `storage` | OS key provider, authenticated encryption, permissions, locking and migration |
12
+ | `credentials`, `otp` | Secret input and challenge-scoped Messages lookup |
13
+ | `output`, `errors` | Output filtering and safe errors |
14
+ | `ui` | Clack terminal prompts, validation, cancellation and fixed progress labels on stderr |
15
+ | `types`, `config` | Checked JSDoc, compatibility metadata and non-secret settings |
16
+
17
+ An authenticated command locks storage, loads/migrates the vault, ensures an app session, discovers capabilities, obtains GP/bearer context as needed and executes the requested operation. Rotated cookies and tokens are saved. Clinical data leaves the process only as requested output or exports; it is not cached in the vault.
18
+
19
+ This is a single-account tool. Login binds saved state to a credential-email digest. Changing known injected credentials requires logout with `--forget`. Document paths use the authenticated account identifier; arbitrary NHS numbers and proxy switching are not exposed.
20
+
21
+ New methods must use existing session/capability abstractions. A generated client method is evidence of a route, not an access guarantee. Preserve provider boundaries and return `unsupported` for unmapped implementations. Never normalize missing data into an empty successful result.
22
+
23
+ The presentation layer receives fixed authentication phase names, never credentials or response bodies. It is disabled for noninteractive/JSON output.
24
+
25
+ Dependencies are small: `@clack/prompts` provides the terminal UI; `tough-cookie` handles cookie scope; optional `@napi-rs/keyring` handles native storage; Node crypto/filesystem APIs implement the encrypted vault. TypeScript checks JavaScript without a build step. Tests inject external dependencies.
26
+
27
+ The package allowlist includes runtime code, one NHS skill, installation instructions, docs and development/security guidance. Tests and build scripts remain repository files. `npm run build` checks JavaScript and verifies the file list before retaining a tarball in ignored `dist/`. The executable `bin/` files remain tracked source. Tagged releases run the complete validation matrix before publishing via GitHub Actions OIDC; see [releasing](releasing.md).
@@ -0,0 +1,45 @@
1
+ # Secure storage and authentication
2
+
3
+ ## Storage
4
+
5
+ All persistent secret values are inside `vault.enc`: explicitly saved credentials, app cookies, CSRF/bearer tokens, patient-session IDs, remembered-device values and authentication timestamps. AES-256-GCM uses a fresh random 96-bit nonce, 128-bit tag and version-specific associated data for each write. Its envelope contains only version, nonce, tag and ciphertext.
6
+
7
+ The default random 256-bit vault key is stored through `@napi-rs/keyring` 2.0.0 under service `nhs-cli`, account `vault-key-v1`. macOS uses Keychain; Linux must use persistent Secret Service with its default login collection. Secrets are not passed in subprocess arguments. OS credential stores protect against other users, not malicious software already running as the same user. The pinned release maps to source revision `f3449416a1b4bf11b0570f0a49395aacc84c8608`; see its [Linux backend selection](https://github.com/Brooooooklyn/keyring-node/blob/f3449416a1b4bf11b0570f0a49395aacc84c8608/src/linux_credential_builder.rs) and the [Secret Service store's collection semantics](https://docs.rs/dbus-secret-service-keyring-store/latest/dbus_secret_service_keyring_store/).
8
+
9
+ The pinned dependency can fall back to Linux keyutils. The adapter first enumerates its service through the dependency's direct Secret Service API. Before creating a key, it writes a random **non-secret probe** into the exact Entry that will hold the key and verifies that value via Secret Service enumeration. Only that already-bound Entry receives a real key. Failed verification removes the probe and fails. Existing keys are read through direct Secret Service enumeration. Dependency updates must recheck this implementation and native Linux tests.
10
+
11
+ Headless mode requires `NHS_CLI_STORAGE=encrypted-file` and separately injected `NHS_CLI_STATE_KEY`. It uses the same encrypted format with an externally managed key. Missing or wrong keys never cause an existing vault to be overwritten. Restore the original key or explicitly start over.
12
+
13
+ Default storage is `$XDG_DATA_HOME/nhs-cli`, or `~/.local/share/nhs-cli`. `NHS_CLI_DATA_DIR` selects another absolute directory. Directories use `0700`; files use `0600`. Unsafe ownership, file permissions and symlink vaults are rejected. Writes use an exclusive private temporary file, fsync and atomic rename.
14
+
15
+ `operation.lock` serializes authenticated commands, credential changes and migration. A second process waits at most ten seconds. Locks are never stolen. After a crash, verify no NHS CLI process is running before removing the lock directory or abandoned ciphertext temporary files.
16
+
17
+ ## Lifecycle
18
+
19
+ 1. Validate stored app state with `GET /v1/session`, updating tokens, patient context and cookies.
20
+ 2. Extend a still-valid session near its inactivity deadline during active work with `POST /v1/session/extend`.
21
+ 3. For GP operations, obtain an asserted identity, validate its OAuth callback and create the GP session.
22
+ 4. For NHS inbox operations, renew the bearer token with `/v1/patient/authorization/access-token/refresh` when needed.
23
+ 5. On confirmed expiry, permit one credential sign-in using remembered-device state. NHS may require MFA again. There is no background keepalive.
24
+
25
+ These are separate protocols. Bearer renewal is not an NHS-login refresh-token grant and cannot establish an expired app session. The CLI does not emulate biometric keys or claim passkey support.
26
+
27
+ Authorization generates a PKCE verifier/challenge, nonce and state. Cookie parameters must match; callbacks must have the expected HTTPS origin, exact path and state. The app session endpoint receives code, verifier and nonce. Decoding a JWT expiry is only a refresh hint, never signature verification.
28
+
29
+ Cookies follow domain, path, expiry and Secure rules. Redirects are bounded to ten and supported HTTPS origins. Requests have 30-second deadlines and bounded bodies. Codes and ID tokens remain transient. Remembered-device body and cookie values are separate.
30
+
31
+ The observed `VERIFIED` mobile challenge enters the SMS flow; unsupported TOTP/landline/registration steps return `auth_required`, and unexpected states return `auth_flow_changed`. Remember-device selection is sent explicitly after SMS verification. Permission failures, outages and throttling do not trigger password resubmission. A rejected bearer token first checks the app session and attempts token renewal there; it does not automatically imply password login. Long server cooldowns surface a failure instead of blocking indefinitely.
32
+
33
+ ## Credentials, migration and logout
34
+
35
+ Credentials resolve from injection, saved values, then Clack terminal prompts when allowed. Email and OTP entry are visible; passwords are masked, including on cancellation. Visible input is confined to terminal stderr, never diagnostics or JSON. Redirected stderr disables interactive input. `--no-prompt` disables prompts and progress; JSON mode suppresses progress while still allowing explicitly interactive input on terminal stderr. Injection never automatically saves passwords. `--save-credentials` verifies through fresh login; `--migrate-credentials` explicitly copies original macOS entries and leaves them intact.
36
+
37
+ Legacy migration whitelists authentication fields and verifies the encrypted replacement before deleting the source. A source digest inside the encrypted vault permits completing interrupted deletion without importing stale state over rotated sessions. A changed source raises `migration_conflict` and preserves both copies. `auth status` and `doctor` never migrate. Failure preserves the source. Deletion does not remove historical snapshots/backups.
38
+
39
+ Logout clears session/device material despite remote failures and reports whether server deletion was acknowledged. `--forget` also removes credentials and the account binding. The OS vault key remains to read the cleared vault. Externally injected credentials and NHS remembered-device registrations remain managed through their own source or official service.
40
+
41
+ ## Diagnostics
42
+
43
+ `doctor` checks storage without creating keys or printing values. `auth status` reports saved-material presence without contacting NHS. OS unlock prompts are outside `--no-prompt`, which controls CLI prompts.
44
+
45
+ Native exception messages and upstream bodies never appear in output. `--debug` cannot enable raw diagnostics. Read-command output and explicit exports intentionally contain health information and must be handled accordingly.
package/docs/cli.md ADDED
@@ -0,0 +1,35 @@
1
+ # CLI contracts
2
+
3
+ See `nhs --help`. Options accept `--name=value` or `--name value`; boolean flags cannot take values. Unknown/duplicate options fail. No secret has an argument flag.
4
+
5
+ `--version` reports the installed package version. Both `nhs` and the legacy `nhs-prescriptions` executable use the same version and implementation. Install the single `nhs` agent skill using [INSTALL.md](../INSTALL.md). Error metadata is limited to integer HTTP `status` and string `capability`; arbitrary details cannot override the public error envelope.
6
+
7
+ New reads return `{ok:true, resource, checkedAt, data}`. Data preserves documented upstream structure; the CLI does not interpret clinical results. Authentication fields are recursively removed. Empty lists require a valid response structure.
8
+
9
+ Prescription status retains `{ok, checkedAt, summary, courses}`. Courses include `id`, `name`, `details`, `requestable`. Orders add `order`; previews contain IDs, names and the exact note. Only the observed HTTP 201 acknowledgement reports successful submission; unrecognized acknowledgements are uncertain.
10
+
11
+ NHS inbox defaults to `index=0`, `count=20`, bounded to index 100000 and count 100. `messages` and `canLoadMore` support explicit subsequent pages. GP pagination is not invented. History defaults to six months. Results accept an ID or historical year. Document `get` returns metadata; `download --output` fetches content.
12
+
13
+ Capabilities return `{status,evidence}` per domain. Status is `available`, `unavailable`, or `unsupported`; this is advertised configuration, not guaranteed endpoint permission. Prescriptions and GP appointments support IM1; GP Connect prescription ordering is not implemented. Results support the classic record path; the version-3 results provider is unsupported. Documents use GP Connect.
14
+
15
+ Errors return `{ok:false,code,message}` with selected metadata such as HTTP status/capability. JSON is selected with `--json` or non-TTY stdout; human errors use stderr. Failures, including failed doctor checks, exit 1. Success exits 0. Agents should parse JSON only.
16
+
17
+ | Code | Action |
18
+ | --- | --- |
19
+ | `auth_required`, `session_expired` | Arrange terminal login; never collect credentials/OTP in chat |
20
+ | `secure_storage_unavailable` | Unlock/configure the OS keyring; no plaintext workaround |
21
+ | `storage_key_required`, `storage_key_missing`, `storage_corrupt` | Restore/configure the key; do not overwrite the vault |
22
+ | `storage_busy` | Wait; inspect before repairing a stale lock |
23
+ | `account_changed` | Stop; changing accounts requires explicit logout with `--forget` |
24
+ | `capability_unavailable`, `unsupported`, `access_denied` | Report the limitation, not an empty clinical result |
25
+ | `auth_flow_changed`, `oauth_validation_failed`, `invalid_response` | Stop and report the code without live response attachments |
26
+ | `rate_limited`, `upstream_unavailable`, `network_error` | Report the failure; do not loop or trigger repeated SMS |
27
+ | `order_requires_scope`, `order_requires_confirmation`, `order_invalid_scope` | Obtain fresh scope and explicit user authorization |
28
+ | `order_unknown` | Check the official app before any new submission |
29
+ | `export_failed` | Choose a new file; existing files are never replaced |
30
+
31
+ Interactive login uses Clack with visible email and OTP fields and a masked password. Prompts require terminal stdin and stderr. Ctrl-C or closed input returns `auth_cancelled`. Progress uses stderr and is suppressed for JSON, redirected stdout, and `--no-prompt`; JSON contracts remain unchanged. Use `--json --no-prompt` for agent calls.
32
+
33
+ `--no-login` prevents password sign-in but permits session validation, bearer refresh and GP uplift. `--no-prompt` disables CLI prompts. `--messages-otp` opts into Messages lookup; `--force-otp` bypasses only the local cooldown.
34
+
35
+ Legacy `nhs-prescriptions otp` now requires `--messages-otp` and reports presence only. Doctor no longer requires optional Messages/sqlite on Linux. Diagnostic details and authentication errors are clarified; prescription data output remains compatible.
@@ -0,0 +1,65 @@
1
+ # Releasing NHS CLI
2
+
3
+ Releases require an explicit maintainer request. Routine checks do not authorize publishing, pushing, changing repository visibility, or account changes. Never use live NHS data to validate a release.
4
+
5
+ ## Local preparation
6
+
7
+ Use Node 22 or 24:
8
+
9
+ ```sh
10
+ npm ci
11
+ npm run build
12
+ npm test
13
+ npm run test:package
14
+ NHS_CLI_TEST_KEYRING=1 npm run test:keyring
15
+ ```
16
+
17
+ The native test creates and removes a unique synthetic keyring entry. The package test installs into a temporary prefix and uses synthetic encrypted-file storage, never the user's vault. `build` emits a tarball under ignored `dist/` and rejects unexpected package paths; inspect its actual contents as well. Keep the tracked `bin/` entrypoints. Validate the NHS skill and review command/installer docs whenever behavior changes.
18
+
19
+ Before making the repository public or publishing, inspect the working tree, all reachable history, and package contents for secrets, patient information, captured responses, and research binaries. Do not print suspect values in review logs. Preserve the keyring pin and Linux Secret Service checks.
20
+
21
+ ## One-time npm bootstrap
22
+
23
+ Use npm 11.19.1 for bootstrap and trusted-publisher setup. If necessary, run that version with `npx --yes npm@11.19.1 <command>` without changing the user's global npm installation. Authenticate with npm's interactive browser login and complete required 2FA privately. Never put authentication tokens in the repository or GitHub Actions secrets.
24
+
25
+ Prepare `@steve228uk/nhs-cli@0.0.1` in an isolated temporary directory with only `package.json`, `LICENSE`, and a README identifying it as a non-functional bootstrap for the upcoming `0.1.0` release. Include the correct public repository URL and MIT license; no scripts, dependencies, executable, or health data. Inspect its `npm pack --dry-run` output before publishing from that directory:
26
+
27
+ ```sh
28
+ npm publish --access public --tag bootstrap
29
+ ```
30
+
31
+ The main source tree stays at `0.1.0`. Verify the `0.0.1` registry record before continuing. Do not unpublish/reuse versions or silently substitute another package name on failure.
32
+
33
+ Push the reviewed code and workflow to `main`, then make `steve228uk/nhs-cli` public as authorized. This enables unauthenticated skill downloads and public provenance.
34
+
35
+ Configure the package's trusted publisher (npm 11.15+ supports this command):
36
+
37
+ ```sh
38
+ npm trust github @steve228uk/nhs-cli --repo steve228uk/nhs-cli --file publish.yml --allow-publish
39
+ npm trust list @steve228uk/nhs-cli
40
+ ```
41
+
42
+ This requires package ownership and account-level 2FA. Equivalent npm website settings are owner `steve228uk`, repository `nhs-cli`, workflow filename `publish.yml`, no environment, with direct `npm publish` enabled. The filename must match exactly; do not enter the `.github/workflows/` prefix. See [npm trust](https://docs.npmjs.com/cli/v11/commands/npm-trust/) and [trusted publishing](https://docs.npmjs.com/trusted-publishers/).
43
+
44
+ ## Tagged releases
45
+
46
+ Keep `package.json` and the lockfile version aligned. Commit and push the reviewed release to `main`; wait for CI before creating the annotated version tag:
47
+
48
+ ```sh
49
+ git tag -a v0.1.0 -m 'Release nhs-cli 0.1.0'
50
+ git push origin v0.1.0
51
+ ```
52
+
53
+ The publish workflow verifies a stable `vX.Y.Z` tag matching the package/lockfile and a commit reachable from `main`. It runs the reusable macOS/Linux × Node 22/24 suite, including native storage checks. Only after all jobs succeed does a GitHub-hosted Ubuntu job build and test the tarball, then publish it as `latest` with OIDC and provenance. Only that job has `id-token: write`; no long-lived npm token is used. Release builds use Node 24 and npm 11.19.1 without dependency caching.
54
+
55
+ On a workflow failure, inspect the safe build/test output. Before repeating a publish attempt, check the registry: a network failure can occur after npm accepted a version. If the version exists, verify it instead of attempting to overwrite it or moving its tag to different code. Fix a published defect in a new patch release.
56
+
57
+ ## Verify the release
58
+
59
+ ```sh
60
+ npm view @steve228uk/nhs-cli@0.1.0 version dist.integrity dist.attestations --json
61
+ npm view @steve228uk/nhs-cli dist-tags --json
62
+ npm run test:package -- @steve228uk/nhs-cli@0.1.0
63
+ ```
64
+
65
+ Verify `latest` points to `0.1.0`, provenance links to the intended GitHub workflow, and public README/installer/tagged skill URLs load. The bootstrap tag may remain as historical setup metadata. Test skill installation in an isolated location and report any Grokbot runtime validation that could not be performed. Record actual checks in `docs/validation.md`; distinguish local results from hosted matrix and live account verification. No login, clinical reads, or prescription submissions belong in these release checks.
@@ -0,0 +1,39 @@
1
+ # Validation record
2
+
3
+ ## Release preparation, 2026-09-06
4
+
5
+ - Node 22.22.3/macOS: checked JavaScript/JSDoc and all 75 synthetic tests pass. The previously flaky lock test now checks mutual exclusion without assuming caller scheduling order. New regressions cover retry cooldowns, capability states, and error metadata filtering.
6
+ - `npm run build` produces a 30-file tarball containing executable source, the single NHS skill, installation instructions, license and docs. `npm run test:package` passes for both executable names and synthetic encrypted-file diagnostics in an isolated installation.
7
+ - The opt-in native Keychain test passes, including persistence in a separate process and cleanup of its unique synthetic entry. No real NHS vault or account credentials were inspected.
8
+ - The consolidated `nhs` skill passes the skill-creator validator. A real shared-skills CLI installation into an isolated temporary Codex project succeeds and copies the canonical file unchanged.
9
+ - Independent instruction walkthroughs cover missing Grokbot local execution, fresh and existing installations, terminal-only OTP handling, existing prescription authorization, and uncertain submission outcomes. The locking regression passes 20 additional focused runs.
10
+ - A targeted scan reviewed 48 unique historical blobs across the two pre-release commits and 46 working files. No private-key, provider-token, JWT, non-example email, machine-home-path, or sensitive-artifact candidates were found. This scan is evidence for the release review, not proof that arbitrary secrets cannot exist.
11
+ - Runtime and dependency behavior are preserved; native keyring versions and Linux libc selectors remain unchanged. Publication is enabled explicitly, with the one-time `0.0.1` bootstrap followed by the `publish.yml` OIDC workflow.
12
+
13
+ The unscoped `nhs-cli` bootstrap was rejected by npm as too similar to another package. The maintainer approved `@steve228uk/nhs-cli`; executable names and storage identity remain unchanged. Hosted matrix and registry publication results will be recorded after those operations complete. Grokbot instructions follow the inspected iMessage repository's skill-write/ExternalShell contract; a real Grokbot session has not been exercised. No live NHS request was made during release preparation.
14
+
15
+ ## Earlier implementation validation
16
+
17
+ The following records describe checks before release preparation, when two skills and the private-package guard were still present. They are retained as historical evidence, including the earlier explicitly scoped live checks.
18
+
19
+ Implementation checks on macOS, 2026-09-06:
20
+
21
+ - `npm run check`: checked JavaScript/JSDoc passes.
22
+ - `npm test`: 72 synthetic tests pass on Node 22 and Node 24; no NHS connections.
23
+ - `NHS_CLI_TEST_KEYRING=1 npm run test:keyring`: macOS persistence across separate processes, deletion, missing-key and oversized-key rejection pass on Node 22 and 24. The unique synthetic entry is removed. Linux-only integration checks are skipped on macOS.
24
+ - Both repository skills pass the skill-creator validator.
25
+ - Package dry-run contains only the allowlisted runtime, skills, license and documentation; `private: true` remains enabled. No package was published.
26
+ - All eight file blobs in the single-commit repository history and the working files were inspected for private-key markers, provider-token formats, JWTs, email literals and machine-specific home paths. Email candidates are examples on `example.com`; no real secrets were found. This is a targeted review, not proof that arbitrary secrets can never exist.
27
+ - Android base and all 19 splits passed signer/content verification as described in [API research](api-research.md).
28
+
29
+ The CI workflow defines macOS/Linux × Node 22/24, including a disposable unlocked GNOME Secret Service for Linux. Hosted matrix results are pending execution of that workflow; local macOS results are not evidence that Linux has passed. Locked-service and permission failures use injected native-adapter failures in the ordinary suite, without locking the user's real Keychain.
30
+
31
+ Authentication tests cover reuse/rotation, fresh GP uplift, remembered-device renewal, SMS and unsupported MFA, expiry, one-attempt recovery, bearer renewal and failure, callback/cookie isolation and bounded retries. Storage tests cover authenticated encryption, wrong keys/tampering, private files, interrupted replacement, process concurrency and migration failure/recovery. Domain tests cover capability gates, malformed containers, message read-state preservation, bounded inbox pages, document scope, exact prescription previews and ambiguous submissions without retries.
32
+
33
+ Explicitly requested live checks on 2026-09-06 used CLI 0.1.0 with web compatibility version 4.76.3 on Node 24.15.0/macOS. The user completed `auth login --save-credentials` in their terminal. Local status confirmed saved session, credentials and remembered-device material without exposing values. Two separate installed-package `capabilities --json --no-login --no-prompt` invocations succeeded, followed by `prescriptions list --json --no-login --no-prompt`. Clinical output remained in process memory; only success/error metadata was recorded. Public OAuth bootstrap validation also passed.
34
+
35
+ These checks verify current login, secure persistence, session reuse, capability discovery and the current-medicines read for this account. They do not independently verify expired-session recovery, every MFA branch, GP uplift during this particular run, other read adapters, or native-app traffic. No prescription submission or other clinical write was performed. Future live checks remain explicitly scoped; patient output must never become fixtures.
36
+
37
+ Clack prompt tests exercise the real renderer with synthetic terminal streams: visible email/OTP, password masking, correction of invalid codes, cancellation and closed input. Redirected streams and no-prompt mode fail without requesting input; agent progress stays silent.
38
+
39
+ Follow-up preflight on 2026-09-06 confirmed the ARM64 XAPK remains available, but Android Studio/SDK/AVD directories and emulator/ADB/mitmproxy executables were not found in the checked locations. The [runtime inspection runbook](android-network-inspection.md) and evidence template are documented; their device/proxy commands have not been exercised on this machine. No runtime capture is claimed.
package/package.json CHANGED
@@ -1,19 +1,56 @@
1
1
  {
2
2
  "name": "@steve228uk/nhs-cli",
3
- "version": "0.0.1",
4
- "description": "Bootstrap placeholder for the upcoming unofficial NHS CLI release.",
5
- "license": "MIT",
3
+ "version": "0.1.0",
4
+ "description": "Unofficial NHS App CLI with secure persistent authentication and read access to health services.",
6
5
  "repository": {
7
6
  "type": "git",
8
7
  "url": "git+https://github.com/steve228uk/nhs-cli.git"
9
8
  },
10
9
  "homepage": "https://github.com/steve228uk/nhs-cli#readme",
11
- "files": [
12
- "README.md",
13
- "LICENSE"
14
- ],
10
+ "bugs": {
11
+ "url": "https://github.com/steve228uk/nhs-cli/issues"
12
+ },
15
13
  "publishConfig": {
16
14
  "access": "public",
17
15
  "registry": "https://registry.npmjs.org/"
16
+ },
17
+ "type": "module",
18
+ "bin": {
19
+ "nhs": "bin/nhs.mjs",
20
+ "nhs-prescriptions": "bin/nhs-prescriptions.mjs"
21
+ },
22
+ "scripts": {
23
+ "check": "tsc --noEmit",
24
+ "build": "npm run check && node scripts/build.mjs",
25
+ "test": "node --test test/*.test.mjs",
26
+ "test:package": "node scripts/test-package.mjs",
27
+ "test:keyring": "node --test test/integration/keyring.test.mjs"
28
+ },
29
+ "engines": {
30
+ "node": ">=22"
31
+ },
32
+ "license": "MIT",
33
+ "files": [
34
+ "bin/",
35
+ "src/",
36
+ "skills/",
37
+ "README.md",
38
+ "INSTALL.md",
39
+ "LICENSE",
40
+ "AGENTS.md",
41
+ "CONTRIBUTING.md",
42
+ "SECURITY.md",
43
+ "docs/"
44
+ ],
45
+ "dependencies": {
46
+ "@clack/prompts": "1.7.0",
47
+ "tough-cookie": "6.0.2"
48
+ },
49
+ "optionalDependencies": {
50
+ "@napi-rs/keyring": "2.0.0"
51
+ },
52
+ "devDependencies": {
53
+ "@types/node": "^22.0.0",
54
+ "typescript": "7.0.2"
18
55
  }
19
56
  }
@@ -0,0 +1,74 @@
1
+ ---
2
+ name: nhs
3
+ description: Use NHS CLI for NHS App records, medicines, results, appointments, messages and documents; recover secure login, export requested data, and submit only explicitly authorized repeat-prescription requests.
4
+ ---
5
+
6
+ # NHS CLI usage
7
+
8
+ Use `nhs --help` to check the installed commands. Use `--json --no-prompt` for agent calls. All clinical output is sensitive: show only what the user needs for this task. Never send it to unrelated tools, logs, issues or third-party services. Do not infer clinical advice from results.
9
+
10
+ Run the CLI on the user's configured computer, where their secure login is stored. In Grokbot, use `ExternalShell` on the user's Mac, never Grokbot's own hosted computer. If local execution is unavailable, direct the user to [Local execution](grokbot://app/v1/settings?id=local-execution). For missing CLI/skill setup, follow [the installer](https://github.com/steve228uk/nhs-cli/blob/main/INSTALL.md). Do not create a teammate or schedule health-data reads during setup.
11
+
12
+ ## Authentication
13
+
14
+ Run `nhs auth status --json` for local saved-material status. It does not authenticate or establish server validity. Run `nhs doctor --json` for value-free storage diagnostics. A valid session is reused across invocations; commands may renew sessions or authenticate using configured credentials. Use `--no-login` when the user wants no credential sign-in.
15
+
16
+ For `auth_required`, arrange for the user to run `nhs auth login` in their terminal. Clack shows email and OTP entry and masks the password; prompts require terminal stdin and stderr. `auth_cancelled` means the user cancelled or closed input; do not retry automatically. `--save-credentials` explicitly persists verified credentials; `--reauth` deliberately signs in again. Never collect passwords, email credentials, OTPs or encryption keys in chat or arguments. Never inspect a vault, Keychain entry or secret environment variable. Do not generate a replacement key to work around a missing key.
17
+
18
+ Storage errors require unlocking/configuring the keyring or restoring the separately injected headless key. There is no plaintext fallback. `--messages-otp` is opt-in, macOS-only and limited to NHS messages after the current challenge. Do not add it without authorization. Do not bypass OTP cooldowns unless another code was intentionally requested.
19
+
20
+ For NHS login, use the CLI's terminal entry or its explicitly authorized `--messages-otp` flow even when another iMessage skill is installed. Do not use a general OTP skill's paste-in-chat fallback or message-deletion routine. If terminal interaction is unavailable, have the user open their own terminal; do not attempt to collect or forward login secrets through agent tools.
21
+
22
+ ## Read the requested data
23
+
24
+ Start with `nhs capabilities --json --no-prompt` when service availability is unknown. `available` reflects advertised capability, not guaranteed permission. Report `capability_unavailable`, `unsupported` or `access_denied` explicitly; never describe them as empty records.
25
+
26
+ | Need | Command |
27
+ | --- | --- |
28
+ | Current medicines | `nhs prescriptions list --json --no-prompt` |
29
+ | Request history | `nhs prescriptions history --json --no-prompt` |
30
+ | GP record sections | `nhs records --json --no-prompt` |
31
+ | Results | `nhs results list --json --no-prompt` |
32
+ | Previous results | `nhs results list --year=2025 --json --no-prompt` |
33
+ | One result | `nhs results get <returned-id> --json --no-prompt` |
34
+ | Appointments / slots | `nhs appointments list --json --no-prompt` / `nhs appointments slots --json --no-prompt` |
35
+ | NHS inbox | `nhs messages list --source=nhs --index=0 --count=20 --json --no-prompt` |
36
+ | GP inbox | `nhs messages list --source=gp --json --no-prompt` |
37
+ | Message | `nhs messages get <returned-id> --source=nhs --json --no-prompt` |
38
+ | Account / pharmacy | `nhs profile --json --no-prompt` / `nhs pharmacy --json --no-prompt` |
39
+ | Documents | `nhs documents list --json --no-prompt` |
40
+ | Document metadata | `nhs documents get <returned-id> --json --no-prompt` |
41
+
42
+ Use IDs from the requested account's current output. Never invent identifiers or switch patient context. Follow NHS inbox `canLoadMore` with bounded explicit pages only when needed. Do not paginate forever. Preserve access/error indicators in GP sections. Message reads intentionally omit read-status updates.
43
+
44
+ New reads have `{ok, resource, checkedAt, data}`; prescriptions retain `{ok, checkedAt, summary, courses}`. Parse structured error `code`, not prose. On rate limits or outages, report the problem without repeated sign-ins. On a changed API response, stop rather than guessing new endpoints.
45
+
46
+ ## Exports and actions
47
+
48
+ Persist health data only when an export/download was requested. Use `--output=<new-file>`; document downloads require `nhs documents download <returned-id> --output=<new-file>`. Choose the user's destination and explain that the exported file contains sensitive information. Existing files are never overwritten.
49
+
50
+ Logout only when requested. `nhs auth logout` clears session/device material; `--forget` additionally removes CLI-managed credentials. Neither is a routine troubleshooting step because both remove useful saved state.
51
+
52
+ ## Repeat-prescription requests
53
+
54
+ Read current medicines with `nhs prescriptions list --json --no-prompt`. Select the exact returned IDs matching the user's requested medicines, then create a fresh preview:
55
+
56
+ ```sh
57
+ nhs prescriptions order --ids=id-1,id-2 --dry-run --json --no-prompt
58
+ ```
59
+
60
+ Show the full selected names and the user's exact note. Include the same `--note` in both preview and submission when supplied; never infer a note, change dosage, or broaden the selection. Use `--all-requestable` only when the user explicitly authorizes all medicines shown in the fresh preview.
61
+
62
+ Submitting a request changes healthcare data. Require explicit authorization for the exact medicines and note. Existing authorization for that scope in the current conversation remains valid; do not ask again merely because this skill is active. A general request to manage prescriptions does not authorize an unspecified order.
63
+
64
+ Once the preview matches the authorized scope:
65
+
66
+ ```sh
67
+ nhs prescriptions order --ids=id-1,id-2 --confirm --json --no-prompt
68
+ ```
69
+
70
+ The command checks current requestability again. Unknown, duplicate, or unavailable IDs stop submission. If scope changes, refresh the preview and resolve the changed scope with the user. Report acknowledgement as a submitted request, not GP approval or pharmacy dispatch.
71
+
72
+ On `order_unknown`, do not retry. Have the user check the official NHS App before authorizing a new submission. The CLI never automatically repeats an ambiguous submission. The compatible `nhs-prescriptions` entrypoint remains available, but no separate skill is needed.
73
+
74
+ Other healthcare writes, patient switching and third-party portal integrations are unsupported. Message reads omit read-status updates; do not add them through another tool.