diff --git a/docs/1-requirements.md b/docs/1-requirements.md
new file mode 100644
index 0000000..838fe1c
--- /dev/null
+++ b/docs/1-requirements.md
@@ -0,0 +1,149 @@
+# Requirements: natsClient_JS
+
+## 1. Business Context & Success Metrics
+
+### Business Goal
+
+Provide a single, reusable NATS WebSocket client for Svelte-based consuming applications. It
+handles the tedious, error-prone parts of talking to a NATS broker — connection lifecycle,
+reconnection, message decoding, request/reply, and msghandler envelope handling — so consuming
+apps can subscribe, publish, request, and reply without duplicating that logic.
+
+### User Stories
+
+- **US-001**: As a consuming app, I want to establish a NATS connection with reactive status so
+ that I can display connectivity to the user.
+- **US-002**: As a consuming app, I want to subscribe to a subject and receive decoded messages so
+ that I can react to events.
+- **US-003**: As a consuming app, I want to publish string or JSON messages so that I can emit
+ events.
+- **US-004**: As a consuming app, I want to use request/reply for synchronous responses so that I
+ can call backend functions.
+- **US-005**: As a consuming app, I want to register a reply handler so that I can serve requests.
+- **US-006**: As a consuming app, I want msghandler envelope wrapping/unwrapping so that I can talk
+ to the sommpanion db backend.
+- **US-007**: As a consuming app, I want automatic reconnection so that I don't lose connectivity
+ on a network blip.
+- **US-008**: As a consuming app, I want a clean disconnect that releases every subscription and
+ the underlying socket.
+
+### KPIs & Targets
+
+- **KPI-001**: 100% of exported API functions covered by automated tests (validates FR-001..008).
+- **KPI-002**: A disconnected connection returns to the `connected` state after automatic
+ reconnection (validates NFR-102).
+
+## 2. Technical Boundaries
+
+### In Scope
+- Connection lifecycle (`getNats`, `connectNATS`, `closeNats`).
+- Subscribe / publish / request / reply.
+- Connection-status tracking via a Svelte store.
+- msghandler envelope packing/unpacking via `msghandler-csr.js`.
+- URL resolution from explicit options, env vars, or config.
+
+### Out of Scope
+- Business logic of consuming apps (this library only moves bytes).
+- Broker-side configuration or server deployment.
+- Any UI components.
+
+### Dependencies
+- `nats.ws` — NATS WebSocket transport.
+- `svelte/store` — reactive `connectionStatus`.
+- `./msghandler-csr.js` — msghandler `smartpack` / `smartunpack`.
+- NATS broker at `wss://natsws.yiem.cc`.
+
+### Deployment Constraints
+- **NFR-101**: Transport must be WebSocket (`nats.ws`) so it works in browsers behind proxies.
+- **NFR-501**: `closeNats` must unsubscribe all subscriptions and clear reconnect timers.
+
+### System Context (C4 Level 1)
+
+```mermaid
+%% C4 Level 1 - System Context
+flowchart LR
+ app[Consuming App
Svelte app]
+ system[(natsClient.js
NATS client lib)]
+ extNats[NATS
Broker wss://natsws.yiem.cc]
+ extMsg[msghandler-csr.js
Envelope codec]
+
+ app -->|imports| system
+ system -->|nats.ws WSS| extNats
+ system -->|smartpack/smartunpack| extMsg
+```
+
+## 3. Functional Requirements (FR)
+
+### FR-001: Establish a connection with URL resolution
+The library shall resolve the broker URL by precedence: `opts.servers`, then
+`import.meta.env.VITE_NATS_URL`, then `config.nats_server_info.url`, then `wss://natsws.yiem.cc`.
+- `getNats` transitions status to `connecting` then `connected`.
+**Traceability**: US-001
+
+### FR-002: Subscribe and decode messages
+The library shall decode each message with `StringCodec`, then `JSON.parse` it, falling back to
+`{ text }` when the payload is not valid JSON.
+- `onMessage(parsed)` is called for each decoded message.
+**Traceability**: US-002
+
+### FR-003: Publish messages
+The library shall stringify a non-string payload with `JSON.stringify`, or send a string payload
+verbatim.
+**Traceability**: US-003
+
+### FR-004: Request/reply
+The library shall send a request and await the reply, with an optional `timeout`.
+**Traceability**: US-004
+
+### FR-005: Reply handler
+The library shall subscribe to a subject, invoke `handler(parsed, msg)`, and publish the returned
+value back on `m.subject`.
+**Traceability**: US-005
+
+### FR-006: msghandler request
+The library shall pack `[[db_request, {functioncall, args}, dictionary]]`, send a request, unpack
+the reply, and return the `jsontable`/`dictionary` payload or throw on a `text` payload.
+**Traceability**: US-006
+
+### FR-007: Connection status tracking
+The library shall publish `connecting`, `connected`, `disconnected`, and `error` statuses to the
+`connectionStatus` store.
+**Traceability**: US-001
+
+### FR-008: Close connection
+The library shall unsubscribe every tracked subscription, clear reconnect timers, and close the
+connection.
+**Traceability**: US-008
+
+## 4. Non-Functional Requirements (NFRs)
+
+### 4.1 Performance & Scalability
+- **NFR-102**: Automatic reconnection must restore the `connected` state without re-calling
+ `getNats` from the consumer.
+
+### 4.2 Availability & Reliability
+- **NFR-201**: Status must be observable through a reactive Svelte store (`connectionStatus`).
+- **NFR-302**: Per-message decode errors must not crash the subscription loop (`catch` around
+ decode/parse/handler).
+
+### 4.3 Privacy & Security
+- **NFR-301**: Config (broker URL, fileserver URL) is injected via `setConfig` / options, never
+ hardcoded in a way that leaks secrets across environments.
+
+### 4.4 Observability & Telemetry
+- **Required Logs**: `[NATS] ...` lines for connection, subscription, publish, and status events.
+- **Critical Metrics**: `connectionStatus.state`.
+- **Retention**: N/A (in-memory library state).
+
+## 5. Acceptance Conditions
+
+- [ ] **FR-001**: `getNats` returns a connection and sets `connected` status.
+- [ ] **FR-002**: `subscribe` decodes a JSON message and calls `onMessage`.
+- [ ] **FR-003**: `publish` sends both string and object payloads.
+- [ ] **FR-004**: `request` returns the decoded reply within `timeout`.
+- [ ] **FR-005**: `reply` auto-replies to each request.
+- [ ] **FR-006**: `sendMsghandlerRequest` returns the `dictionary` payload and throws on `text`.
+- [ ] **FR-007**: `connectionStatus` emits `connecting`/`connected`/`disconnected`/`error`.
+- [ ] **FR-008**: `closeNats` unsubscribes all and closes the socket.
+- [ ] **NFR-102**: A disconnect transitions status and auto-reconnects.
+- [ ] **NFR-501**: `closeNats` clears all subscriptions and timers.
diff --git a/docs/2-solution_design.md b/docs/2-solution_design.md
new file mode 100644
index 0000000..993afd5
--- /dev/null
+++ b/docs/2-solution_design.md
@@ -0,0 +1,82 @@
+# Solution Design: natsClient_JS
+
+## 1. Problem Decomposition
+
+| Problem | Description | User Impact |
+|---------|-------------|-------------|
+| P-001 | Consumers must manage a NATS connection lifecycle | Boilerplate, connection churn, dropped sockets |
+| P-002 | Consumers must decode/encode payloads | Manual `StringCodec`/`JSON` in every call site |
+| P-003 | Consumers need synchronous request/reply | Duplicated await-loop logic |
+| P-004 | Consumers need a server-side reply handler | No way to serve requests from the client |
+| P-005 | Consumers need msghandler envelope handling | Manual packing/unwrapping |
+| P-006 | Consumers need to know connection state | No way to drive a status indicator |
+| P-007 | Consumers need clean teardown | Leaked subscriptions and sockets |
+
+## 2. Solution Approach
+
+A single shared NATS connection exposed as ES module exports, with one helper function per
+operation (subscribe, publish, request, reply, msghandler, close). Connection state flows into a
+reactive Svelte store so consumers can bind it directly. Envelope packing delegates to
+`msghandler-csr.js`, keeping this library focused on transport and lifecycle.
+
+## 3. Decision Rationale
+
+| Decision ID | Decision | Rationale | Alternatives Rejected |
+|-------------|----------|-----------|----------------------|
+| SD-001 | Shared module-level connection (`nc`) | One socket serves every operation for the whole app | Per-call `connect` — connection churn |
+| SD-002 | URL resolution precedence chain | Predictable, layered configuration (opts → env → config → default) | A single required URL arg — no env/config fallback |
+| SD-003 | `StringCodec` + `JSON.stringify`/`JSON.parse` | Uniform text encoding for both directions | Per-consumer encoding logic |
+| SD-004 | Monitor `nc.status()` and `nc.closed()` | Reactive `connecting`/`connected`/`disconnected`/`error` states | Polling the connection |
+| SD-005 | Subscription registry (`Map`) | Centralized unsubscribe in `closeNats` | Scattered subscriptions with no cleanup |
+| SD-006 | Delegate msghandler to `msghandler-csr.js` | Separation of envelope codec from transport | Reimplementing envelope logic here |
+| SD-007 | Svelte store for `connectionStatus` | Framework-agnostic consumers get reactivity for free | Plain variable consumers must wire their own subscription |
+
+## 4. High-Level Component Diagram
+
+### C4 Level 2 - Container
+
+```mermaid
+%% C4 Level 2 - Container
+flowchart LR
+ app[Consuming App
Svelte app] -->|imports| natsClient[(natsClient.js)]
+ natsClient -->|nats.ws WSS| nats[(NATS broker)]
+ natsClient -->|smartpack/smartunpack| msg[(msghandler-csr.js)]
+ natsClient -->|writable| store[(connectionStatus store)]
+```
+
+**Component Descriptions**:
+- **natsClient.js**: Shared connection + operation helpers (subscribe/publish/request/reply) +
+ status store + msghandler delegation.
+ - Links to requirements: FR-001..FR-008, NFR-101, NFR-201
+- **msghandler-csr.js**: Envelope pack/unpack.
+ - Links to requirements: FR-006
+- **connectionStatus store**: Reactive `{state, message}` for the app.
+ - Links to requirements: FR-007
+
+## 5. Alternatives Considered
+
+| Alternative | Pros | Cons | Decision |
+|-------------|------|------|----------|
+| Per-call connection | Isolated lifecycle | Connection churn, re-auth overhead | Rejected — SD-001 |
+| Manual decode at call site | No dependency | Duplicated error handling | Rejected — SD-003 |
+| Callbacks instead of async iterators | Familiar | Verbose, harder to cancel | Rejected — uses `for await` |
+
+## 6. Risk Assessment
+
+| Risk | Impact | Probability | Mitigation |
+|------|--------|-------------|------------|
+| Broker unreachable at startup | Connection fails | Medium | `getNats` throws; consumer retries |
+| Decode error on a message | Lost message / crash | Low | `catch` around decode/parse/handler |
+| Reconnect never settles | Stuck `disconnected` | Low | `nc.status()` + `nc.closed()` monitoring |
+
+## 7. Requirements Traceability
+
+| Solution Component | Requirement ID | Decision ID | Description |
+|-------------------|----------------|-------------|-------------|
+| Shared connection | FR-001, FR-003 | SD-001 | One socket for pub/sub and publish |
+| URL resolution | FR-001 | SD-002 | opts → env → config → default |
+| Message decode | FR-002 | SD-003 | StringCodec + JSON/text fallback |
+| Status tracking | FR-007 | SD-004 | status() + closed() monitor |
+| Subscription cleanup | FR-008 | SD-005 | Map registry |
+| msghandler | FR-006 | SD-006 | Delegation to msghandler-csr.js |
+| Reactive status | NFR-201 | SD-007 | Svelte store |
diff --git a/docs/3-walkthrough.md b/docs/3-walkthrough.md
new file mode 100644
index 0000000..0d32a48
--- /dev/null
+++ b/docs/3-walkthrough.md
@@ -0,0 +1,141 @@
+# Walkthrough: natsClient_JS
+
+One section per system participant. Here the single participant is the **consuming app** that
+imports `natsClient.js`. Each step traces the complete flow and cites the Solution Design decision
+(SD-XXX) and Requirement (FR/NFR) it implements.
+
+## Consuming App
+
+### Session Start — Connect
+
+**WT-001**: App calls `getNats()` / `connectNATS()` and the connection goes `connecting` →
+`connected`.
+
+> Cross-reference: `1-requirements.md:FR-001`, `2-solution_design.md:SD-001, SD-002, SD-004`
+
+```mermaid
+sequenceDiagram
+ participant App as Consuming App
+ participant C as natsClient.js
+ participant Nats as NATS broker
+
+ App->>C: getNats({ servers })
+ C->>C: resolve URL (SD-002)
+ C->>Nats: connect (SD-001)
+ Nats-->>C: connected
+ C->>App: connectionStatus = { state: "connected" } (SD-004, SD-007)
+```
+
+**WT-002**: App subscribes to a subject and receives decoded messages.
+
+> Cross-reference: `1-requirements.md:FR-002`, `2-solution_design.md:SD-003`
+
+| Step | Action | System Response | Traceability |
+|------|--------|-----------------|--------------|
+| WT-002.1 | `subscribe('subj', onMessage)` | `nc.subscribe`, tracked in Map (SD-005) | FR-002 |
+| WT-002.2 | Broker sends a message | `StringCodec` decode, `JSON.parse` (SD-003) | FR-002 |
+| WT-002.3 | Payload is valid JSON | `onMessage(parsed)` called | FR-002 |
+| WT-002.4 | Payload is not JSON | `{ text }` fallback, `onMessage` called | FR-002 |
+
+**WT-003**: App publishes a message (object or string).
+
+> Cross-reference: `1-requirements.md:FR-003`, `2-solution_design.md:SD-001, SD-003`
+
+```mermaid
+sequenceDiagram
+ participant App as Consuming App
+ participant C as natsClient.js
+ participant Nats as NATS broker
+
+ App->>C: publish('subj', {a:1})
+ C->>C: JSON.stringify (SD-003)
+ C->>C: nc.publish
+ C->>Nats: publish
+```
+
+**WT-004**: App issues a request and awaits the reply.
+
+> Cross-reference: `1-requirements.md:FR-004`, `2-solution_design.md:SD-003`
+
+```mermaid
+sequenceDiagram
+ participant App as Consuming App
+ participant C as natsClient.js
+ participant Nats as NATS broker
+
+ App->>C: request('subj', payload, { timeout })
+ C->>Nats: request + encode
+ Nats-->>C: reply
+ C->>C: decode + JSON.parse
+ C-->>App: responseJson
+```
+
+**WT-005**: App registers a reply handler to serve requests.
+
+> Cross-reference: `1-requirements.md:FR-005`, `2-solution_design.md:SD-005`
+
+```mermaid
+sequenceDiagram
+ participant App as Consuming App
+ participant C as natsClient.js
+ participant Nats as NATS broker
+
+ App->>C: reply('subj', handler)
+ C->>Nats: subscribe
+ Nats->>C: request
+ C->>C: handler(parsed, msg)
+ C->>Nats: publish(reply, responseMsg)
+```
+
+**WT-006**: App calls `sendMsghandlerRequest` to talk to the sommpanion db backend.
+
+> Cross-reference: `1-requirements.md:FR-006`, `2-solution_design.md:SD-006`
+
+```mermaid
+sequenceDiagram
+ participant App as Consuming App
+ participant C as natsClient.js
+ participant Msg as msghandler-csr.js
+ participant Nats as NATS broker
+
+ App->>C: sendMsghandlerRequest('subj', 'fn', args, config)
+ C->>Msg: smartpack([db_request, {functioncall,args}, dictionary])
+ C->>Nats: request(envelope)
+ Nats-->>C: reply envelope
+ C->>Msg: smartunpack
+ C-->>App: data (dictionary/jsontable) or throw on text
+```
+
+### Error Paths
+
+**WT-007**: Broker disconnects; status transitions then auto-reconnects.
+
+> Cross-reference: `1-requirements.md:FR-007`, `2-solution_design.md:SD-004`, `NFR-102`
+
+```mermaid
+sequenceDiagram
+ participant App as Consuming App
+ participant C as natsClient.js
+ participant Nats as NATS broker
+
+ Nats->>C: disconnect event
+ C->>App: connectionStatus = disconnected (SD-004)
+ Nats->>C: reconnect event
+ C->>App: connectionStatus = connected (SD-004)
+```
+
+**WT-008**: App closes the connection.
+
+> Cross-reference: `1-requirements.md:FR-008`, `2-solution_design.md:SD-005`, `NFR-501`
+
+```mermaid
+sequenceDiagram
+ participant App as Consuming App
+ participant C as natsClient.js
+ participant Nats as NATS broker
+
+ App->>C: closeNats()
+ C->>C: unsubscribe all tracked subs (SD-005)
+ C->>Nats: close
+ C->>App: connectionStatus = disconnected
+```
diff --git a/docs/4-specification.md b/docs/4-specification.md
new file mode 100644
index 0000000..3d19969
--- /dev/null
+++ b/docs/4-specification.md
@@ -0,0 +1,120 @@
+# Specification: natsClient_JS
+
+The technical contract for the module's exports. Each item carries an `SP-XXX` ID and traces to a
+Requirement (FR/NFR) and Solution Design decision (SD).
+
+## 1. Module Exports
+
+- `connectionStatus` — Svelte writable store of `{ state, message }`.
+- `setConfig(cfg)` — inject config (broker/fileserver URLs).
+- `getNats(opts)` — establish the shared connection.
+- `subscribe(subject, onMessage)` — subscribe and decode.
+- `publish(subject, payload, opts)` — publish.
+- `closeNats()` — close and cleanup.
+- `connectNATS(brokerUrl, cfg)` — connect using a broker URL or config.
+- `request(subject, payload, opts)` — request/reply.
+- `reply(subject, handler, opts)` — reply handler.
+- `sendMsghandlerRequest(subject, functioncall, args, config)` — msghandler request.
+
+## 2. API Contract
+
+### SP-001: getNats(opts)
+
+```
+getNats(opts?: { servers?: string }) => Promise
+```
+- URL resolution precedence: `opts.servers` → `import.meta.env.VITE_NATS_URL` →
+ `config.nats_server_info.url` → `wss://natsws.yiem.cc`.
+- Emits `connecting` then `connected` on `connectionStatus`.
+- Returns the NATS connection object.
+- Throws on connection failure.
+**Traceability**: FR-001, FR-007, SD-001, SD-002, SD-004
+
+### SP-002: subscribe(subject, onMessage)
+
+```
+subscribe(subject: string, onMessage: (parsed) => void) => Promise<{ unsubscribe(): Promise }>
+```
+- Auto-connects via `getNats` if not connected.
+- Decodes each message with `StringCodec`, then `JSON.parse`, falling back to `{ text }`.
+- Registers the subscription in the `Map` registry for cleanup (SD-005).
+**Traceability**: FR-002, SD-003, SD-005
+
+### SP-003: publish(subject, payload, opts)
+
+```
+publish(subject: string, payload: object | string = {}, opts?: object) => Promise
+```
+- Auto-connects via `getNats` if not connected.
+- String payloads are sent verbatim; other payloads are `JSON.stringify`ed.
+**Traceability**: FR-003, SD-001, SD-003
+
+### SP-004: request(subject, payload, opts)
+
+```
+request(subject: string, payload: object | string, opts?: { timeout?: number }) => Promise