letmeknow-cli 0.1.0 → 0.3.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.
Files changed (3) hide show
  1. package/README.md +111 -50
  2. package/SKILL.md +108 -39
  3. package/package.json +5 -2
package/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # LetMeKnow
2
2
 
3
- LetMeKnow gives an agent a temporary interactive web surface for a human. It is not a localhost proxy and does not read directories. A Node CLI carries newline-delimited JSON between stdin/stdout and a Cloudflare Durable Object over one persistent WebSocket.
3
+ LetMeKnow gives an agent a temporary HTML and CSS workspace for a human. The agent renders a page, receives normalized form and button actions, and responds with HTML fragments. The browser runtime handles validation, form serialization, pending state, and targeted updates.
4
+
5
+ It is not a localhost proxy or a programmable frontend. Agents provide presentation and semantic actions, not JavaScript or HTTP handlers.
4
6
 
5
7
  ## CLI
6
8
 
@@ -18,88 +20,156 @@ LETMEKNOW_URL=http://localhost:8787 npx letmeknow-cli
18
20
 
19
21
  stdin contains one compact JSON command per line. stdout contains one JSON event per line. Diagnostics go to stderr.
20
22
 
21
- Print the agent-facing skill file without opening a network connection:
23
+ Print the agent instructions without connecting:
22
24
 
23
25
  ```bash
24
- npx letmeknow-cli --skill > SKILL.md
26
+ npx letmeknow-cli --skill
25
27
  ```
26
28
 
27
- Start a session:
29
+ ## Example
30
+
31
+ Open a session:
28
32
 
29
33
  ```json
30
- {"type":"open","id":"1"}
34
+ {"type":"open","id":"open-1"}
31
35
  ```
32
36
 
33
- stdout returns the URL to share with the human:
37
+ The CLI emits its temporary URL:
34
38
 
35
39
  ```json
36
- {"type":"session","id":"1","url":"https://0123456789abcdef0123.letmeknow.dev/","expires_after_disconnect":600}
40
+ {"type":"session","id":"open-1","url":"https://0123456789abcdef0123.letmeknow.dev/","expires_after_disconnect":600}
37
41
  ```
38
42
 
39
- There is no initial bundle. Initial resources and later updates are the same `put` command:
43
+ The URL immediately serves a styled shell with a waiting message. Send the initial HTML and optional CSS with `render`; a browser that is already open receives it without polling:
40
44
 
41
45
  ```json
42
- {"type":"put","id":"2","path":"/","content_type":"text/html; charset=utf-8","body":"<h1>Hello</h1>"}
43
- {"type":"put","id":"3","path":"/app.js","content_type":"text/javascript","body":"document.body.append(' ready')"}
46
+ {"type":"render","id":"render-1","body":"<h1>Search invoices</h1><form id=\"search\" action=\"search\" method=\"post\" data-lmk-target=\"results\"><label>Customer<input name=\"customer\" required></label><button>Search</button></form><section id=\"results\"><p>Enter a customer.</p></section>","css":"#results { margin-top: 2rem; }"}
44
47
  ```
45
48
 
46
- ## Protocol
49
+ A successful render receives a revision:
47
50
 
48
- ### Commands: stdin to LetMeKnow
51
+ ```json
52
+ {"type":"ack","id":"render-1","render_id":"b87438c2-4f1c-44bd-9875-6cc64370b8aa"}
53
+ ```
49
54
 
50
- - `open` creates the session and emits `session`.
51
- - `put` stores or replaces an exact pathname.
52
- - `delete` removes a stored pathname.
53
- - `response` answers one pending browser request.
54
- - `close` immediately destroys the session.
55
+ Submitting the form produces one normalized action:
55
56
 
56
- All commands accept an optional string `id`. Successful `put`, `delete`, `response`, and `close` commands emit a correlated `ack`.
57
+ ```json
58
+ {"type":"action","id":"event-1","client_id":"8c05cc18-f503-4d1b-aad9-acde3a41c983","render_id":"b87438c2-4f1c-44bd-9875-6cc64370b8aa","action_id":"search","form_id":"search","target_id":"results","trigger":{"id":null,"name":null,"value":null},"values":{"customer":"Acme Ltd"}}
59
+ ```
57
60
 
58
- A resource supports `status`, `headers`, `content_type`, `encoding`, and `body`. `status` defaults to `200`, `encoding` to `utf8`, and `body` to an empty string. Header values may be strings or string arrays; arrays preserve repeated headers such as `Set-Cookie`. `content_type` overrides any `Content-Type` header. Binary bodies use base64:
61
+ Respond with HTML for the target's contents:
59
62
 
60
63
  ```json
61
- {"type":"put","path":"/logo.png","content_type":"image/png","encoding":"base64","body":"iVBORw0KGgo..."}
64
+ {"type":"response","id":"response-1","request_id":"event-1","body":"<table><tr><th>Invoice</th><th>Amount</th></tr><tr><td>INV-42</td><td>$800</td></tr></table>"}
62
65
  ```
63
66
 
64
- Delete a resource:
67
+ The runtime assigns a new render revision and places the fragment inside `#results`. If `data-lmk-target` had been omitted, it would replace the contents of the whole workspace.
65
68
 
66
- ```json
67
- {"type":"delete","id":"4","path":"/old.html"}
69
+ ## HTML actions
70
+
71
+ ### Forms
72
+
73
+ Interactive forms use standard HTML:
74
+
75
+ ```html
76
+ <form id="decision" action="decide" method="post">
77
+ <label>
78
+ Comment
79
+ <textarea name="comment"></textarea>
80
+ </label>
81
+ <button name="decision" value="approve" formaction="approve">Approve</button>
82
+ <button name="decision" value="reject" formaction="reject">Reject</button>
83
+ </form>
68
84
  ```
69
85
 
70
- Destroy everything immediately:
86
+ Requirements:
71
87
 
72
- ```json
73
- {"type":"close","id":"5"}
88
+ - `method="post"`
89
+ - A stable form `id`
90
+ - A relative action identifier such as `search`, `approve`, or `invoice:inspect`
91
+ - Meaningful control `name` values
92
+
93
+ A submit button's standard `formaction` overrides the form's `action`. Native `required`, input types, ranges, and patterns validate locally. `FormData(form, submitter)` is captured before the form is disabled, so selected controls and the clicked submit button are included. Repeated names become string arrays.
94
+
95
+ ### Standalone actions
96
+
97
+ A button can invoke an action without a form:
98
+
99
+ ```html
100
+ <button type="button" data-lmk-action="refresh-status" data-lmk-target="status">
101
+ Refresh
102
+ </button>
74
103
  ```
75
104
 
76
- ### Events: LetMeKnow to stdout
105
+ Its event has `form_id: null`, empty `values`, and the button's optional `id`, `name`, and `value` in `trigger`.
77
106
 
78
- - `session` contains the public URL and disconnect grace period.
79
- - `request` describes a browser request that did not match a stored resource.
80
- - `ack` confirms a command.
81
- - `error` reports a command or protocol error.
82
- - `closing` reports explicit destruction.
107
+ ### Targeted updates
83
108
 
84
- Unknown paths are sent to the producer:
109
+ `data-lmk-target` accepts one element ID without `#`:
85
110
 
86
- ```json
87
- {"type":"request","id":"cf-request-id","method":"POST","path":"/answer","query":"step=2","headers":{"content-type":"application/x-www-form-urlencoded","hx-request":"true"},"encoding":"utf8","body":"answer=yes"}
111
+ ```html
112
+ <button data-lmk-action="load-more" data-lmk-target="results">Load more</button>
113
+ <section id="results"></section>
88
114
  ```
89
115
 
90
- Answer with the request event's `id` as `request_id`:
116
+ All updates use `innerHTML`. There are no alternate swap modes or arbitrary selector targets. The default target is the runtime-owned `lmk-view`, which means the whole workspace.
117
+
118
+ Typing, focusing, expanding `<details>`, native validation, scrolling, and other local browser behavior produce no agent events.
119
+
120
+ ## CSS
121
+
122
+ `render` accepts page-level CSS in its `css` field. A `response` may include `css` to replace the current page CSS; omitting it preserves the current CSS.
123
+
124
+ Normal modern CSS is supported, including grid, flexbox, media queries, variables, transitions, and print styles. External stylesheets, `@import`, scripts, inline event handlers, and inline `style` attributes are blocked. CSS and images may reference session assets with relative URLs.
125
+
126
+ ## Assets
127
+
128
+ `put` stores or replaces passive resources only under `/assets/`:
91
129
 
92
130
  ```json
93
- {"type":"response","id":"6","request_id":"cf-request-id","status":200,"headers":{"content-type":"text/html; charset=utf-8","hx-trigger":"answered"},"body":"<strong>Accepted</strong>"}
131
+ {"type":"put","id":"logo","path":"/assets/logo.png","content_type":"image/png","encoding":"base64","body":"iVBORw0KGgo..."}
132
+ ```
133
+
134
+ Reference them relatively so local path-based sessions also work:
135
+
136
+ ```html
137
+ <img src="assets/logo.png" alt="Company logo">
94
138
  ```
95
139
 
96
- Dynamic responses are not stored. Send a separate `put` to serve a path without involving the producer next time.
140
+ Assets answer only `GET` and `HEAD`. Each body is limited to 1 MiB. A session accepts at most 100 assets and 10 MiB of decoded asset data. Assets are removed with the session; there is no `delete` command.
141
+
142
+ ## Protocol
143
+
144
+ ### Commands
145
+
146
+ - `open`: create the session; it must be first.
147
+ - `render`: set the initial/current HTML and CSS for fresh clients.
148
+ - `put`: store an asset under `/assets/`.
149
+ - `response`: answer one pending action with HTML and optional CSS.
150
+ - `close`: destroy the session immediately.
151
+
152
+ Commands accept an optional string `id`. Successful commands emit correlated `ack` events. `render` and `response` acknowledgements also include the generated `render_id`.
153
+
154
+ ### Events
97
155
 
98
- Production sessions use isolated `*.letmeknow.dev` origins, so root-relative links, forms, and asset URLs work normally. Local sessions use `/s/<code>/`; use relative URLs there. Stored paths ignore the URL query when matching. Dynamic events contain pathname and query separately. Methods, forms, cookies, HTMX headers, SPA API requests, status, response headers, and text or binary bodies pass through generically. Browser request bodies use UTF-8 only for recognized textual media types; absent, unrecognized, or invalid UTF-8 bodies use base64. Request, response, and stored-resource bodies are bounded to 1 MiB and are non-streaming; a stalled dynamic browser request body times out after 30 seconds, and a producer response may take up to 5 minutes. Stored and dynamic responses default to `Cache-Control: no-store`; an explicit producer header overrides that default. A session accepts at most 100 stored resources (10 MiB decoded total) and 32 simultaneous dynamic requests.
156
+ - `session`: the public URL and disconnect grace period.
157
+ - `action`: a normalized form or standalone-button action.
158
+ - `ack`: command completion.
159
+ - `error`: invalid command or protocol state.
160
+ - `closing`: explicit session destruction.
99
161
 
100
- ## Lifecycle
162
+ One interaction per browser client, render, form, and target may be pending at a time. Conflicting submissions are rejected, while independent forms and targets can proceed concurrently. Match responses by action ID rather than event order.
101
163
 
102
- The active CLI connection owns the session. The CLI receives an unguessable private reconnect credential in a private WebSocket message, keeps it off protocol stdout, and sends it as the WebSocket subprotocol on reconnect. The reconnect URL contains only the public session code. If the connection drops unexpectedly, it reconnects with that credential during the ten-minute grace period without requiring another `open` command; each connection attempt has a ten-second deadline, and a failed initial attempt exits nonzero while reconnect attempts continue within the grace period. Stored resources remain available for ten minutes, while unknown paths return `503`. Browser traffic does not extend the grace period. After the alarm fires all resources are deleted. A producer connection that never sends `open` is cleaned up after a short deadline. `close` deletes everything immediately.
164
+ HTML, CSS, asset, and action bodies are each limited to 1 MiB. Up to 32 independent actions may be pending. Action bodies have a 30-second read deadline, and an agent response may take up to five minutes.
165
+
166
+ ## Security and lifecycle
167
+
168
+ HTML fragments are sanitized. Scripts, style elements, inline event handlers, HTMX attributes, frames, active metadata, external form actions, and invalid LetMeKnow attributes are removed. A strict Content Security Policy blocks arbitrary browser connections and external resources. Agent CSS is installed separately in a nonce-protected style element.
169
+
170
+ The URL is a bearer secret. Share it only with the intended human.
171
+
172
+ The CLI owns the session and automatically reconnects after an unexpected disconnect. The shell, current render, and assets remain available during the ten-minute disconnect grace period, but actions fail. Browser traffic does not extend the grace period. `close` destroys everything immediately.
103
173
 
104
174
  ## Development
105
175
 
@@ -107,14 +177,5 @@ The active CLI connection owns the session. The CLI receives an unguessable priv
107
177
  npm install
108
178
  npm run dev
109
179
  npm test
110
- ```
111
-
112
- The Worker uses one Durable Object per session. The object owns the producer WebSocket, stored resources, pending browser requests, and disconnect alarm. No D1 or R2 binding is required.
113
-
114
- Deploy with:
115
-
116
- ```bash
117
180
  npm run deploy
118
181
  ```
119
-
120
- Production subdomain URLs require a proxied `*.letmeknow.dev` DNS record and a Worker route for `*.letmeknow.dev/*` in Cloudflare. The apex `letmeknow.dev` remains the control endpoint.
package/SKILL.md CHANGED
@@ -1,13 +1,15 @@
1
1
  ---
2
2
  name: letmeknow
3
- description: Create a temporary browser surface for a human, serve static resources, and handle interactive HTTP requests through the LetMeKnow NDJSON CLI.
3
+ description: Show a human a temporary HTML and CSS workspace and handle normalized form or button actions through the LetMeKnow NDJSON CLI.
4
4
  ---
5
5
 
6
6
  # LetMeKnow
7
7
 
8
- Use LetMeKnow when a human needs a temporary web page or interactive UI from an agent. It is not a localhost proxy and does not read files or directories.
8
+ Use LetMeKnow when a human needs a temporary rich document, dashboard, report, preview, form, approval, quiz, table, or status view. The agent supplies semantic HTML and CSS. The browser sends only declared actions; typing and other local state do not create events.
9
9
 
10
- ## Start the CLI
10
+ LetMeKnow is not a localhost proxy, persistent application, or arbitrary JavaScript environment.
11
+
12
+ ## Start
11
13
 
12
14
  Node.js 22 or newer is required.
13
15
 
@@ -15,84 +17,151 @@ Node.js 22 or newer is required.
15
17
  npx letmeknow-cli
16
18
  ```
17
19
 
18
- This connects to `https://letmeknow.dev` by default. To use another trusted deployment:
20
+ Run it as a long-lived child process. Write one compact JSON object per line to stdin, keep stdin open, and read one JSON event per line from stdout. Read stderr separately.
19
21
 
20
- ```bash
21
- LETMEKNOW_URL=http://localhost:8787 npx letmeknow-cli
22
+ Open first:
23
+
24
+ ```json
25
+ {"type":"open","id":"open-1"}
26
+ ```
27
+
28
+ Wait for the session URL:
29
+
30
+ ```json
31
+ {"type":"session","id":"open-1","url":"https://0123456789abcdef0123.letmeknow.dev/","expires_after_disconnect":600}
22
32
  ```
23
33
 
24
- Run the CLI as a long-lived child process. Write one compact JSON object per line to stdin, keep stdin open while the session is active, and read one JSON event per line from stdout. Read diagnostics from stderr separately. Do not mix stderr into the NDJSON stream.
34
+ The URL immediately serves a shell with a waiting message. It is safe for the human to open it before the first render.
25
35
 
26
- ## Open and publish static content
36
+ ## Render HTML and CSS
27
37
 
28
- `open` must be the first command. String `id` values are optional; use them to correlate results.
38
+ Send an HTML fragment and optional page CSS:
29
39
 
30
40
  ```json
31
- {"type":"open","id":"open-1"}
41
+ {"type":"render","id":"render-1","body":"<h1>Search invoices</h1><form id=\"search\" action=\"search\" method=\"post\" data-lmk-target=\"results\"><label>Customer<input name=\"customer\" required></label><button>Search</button></form><section id=\"results\"><p>Enter a customer.</p></section>","css":"#results { margin-top: 2rem; }"}
32
42
  ```
33
43
 
34
- Wait for the `session` event and retain its URL:
44
+ A browser already waiting at the URL receives the render. Wait for the acknowledgement:
35
45
 
36
46
  ```json
37
- {"type":"session","id":"open-1","url":"https://0123456789abcdef0123.letmeknow.dev/","expires_after_disconnect":600}
47
+ {"type":"ack","id":"render-1","render_id":"b87438c2-4f1c-44bd-9875-6cc64370b8aa"}
38
48
  ```
39
49
 
40
- Store or replace exact pathnames with `put`. The following page submits to an unstored path so the agent can handle it dynamically:
50
+ Use semantic HTML such as headings, sections, paragraphs, lists, tables, `dl`, forms, labels, controls, buttons, `details`, progress, and images. Do not include `<html>`, `<head>`, `<body>`, `<main id="lmk-view">`, scripts, style elements, inline event handlers, inline `style`, iframes, or HTMX attributes.
41
51
 
42
- ```json
43
- {"type":"put","id":"put-1","path":"/","content_type":"text/html; charset=utf-8","body":"<!doctype html><form method=\"post\" action=\"answer\"><label>Answer <input name=\"answer\"></label><button>Send</button></form>"}
52
+ The built-in stylesheet makes unstyled HTML usable. The optional `css` field supports normal modern CSS, including grid, flexbox, media queries, variables, transitions, and print styles. External stylesheets, `@import`, and remote resources do not work. Use relative asset URLs.
53
+
54
+ ## Forms
55
+
56
+ Interactive forms use standard HTML:
57
+
58
+ ```html
59
+ <form id="decision" action="decide" method="post">
60
+ <label>Reason<textarea name="reason" required></textarea></label>
61
+ <button name="decision" value="approve" formaction="approve">Approve</button>
62
+ <button name="decision" value="reject" formaction="reject">Reject</button>
63
+ </form>
64
+ ```
65
+
66
+ Rules:
67
+
68
+ - Use `method="post"`.
69
+ - Give every interactive form a stable, unique `id`.
70
+ - Give controls meaningful `name` values.
71
+ - Use a relative action identifier containing letters, digits, `.`, `_`, `:`, or `-`.
72
+ - A submit button's standard `formaction` may override the form action.
73
+ - Native `required`, input types, ranges, and patterns validate locally.
74
+
75
+ The runtime captures `FormData(form, submitter)` before disabling the form. Selected radio buttons, checked boxes, ordinary controls, and the clicked submit button are therefore included. Repeated names become string arrays. File values are not currently sent.
76
+
77
+ ## Standalone actions
78
+
79
+ Use a button when an action does not need a form:
80
+
81
+ ```html
82
+ <button type="button" data-lmk-action="refresh-status" data-lmk-target="status">
83
+ Refresh
84
+ </button>
85
+ ```
86
+
87
+ This is appropriate for refresh, retry, cancel, generate, inspect, load-more, and export actions. The event has `form_id: null`, empty `values`, and the button's optional `id`, `name`, and `value` in `trigger`.
88
+
89
+ ## Whole and partial updates
90
+
91
+ By default, a response replaces the contents of the whole workspace. To update a smaller region, put `data-lmk-target="element-id"` on the form or action button:
92
+
93
+ ```html
94
+ <form id="search" action="search" method="post" data-lmk-target="results">
95
+ <input name="query">
96
+ <button>Search</button>
97
+ </form>
98
+ <section id="results"></section>
44
99
  ```
45
100
 
46
- Use relative links, form actions, and asset URLs so pages also work on local deployments, whose session URL includes a path prefix. Wait for `{"type":"ack","id":"put-1"}` before relying on the update. `status` defaults to `200`, `encoding` to `utf8`, and `body` to an empty string. `headers` accepts string values or string arrays; `content_type` overrides `Content-Type`. For binary content, set `encoding` to `base64`. Paths must start with `/` and must not contain a query. Query strings do not affect stored-path matching.
101
+ The target is one bare element ID without `#`. Every update uses `innerHTML`; there are no other swap modes. A submit button or action button may override its form's target.
102
+
103
+ ## Handle actions
47
104
 
48
- Remove static content with:
105
+ A completed interaction produces one normalized event:
49
106
 
50
107
  ```json
51
- {"type":"delete","id":"delete-1","path":"/old.html"}
108
+ {"type":"action","id":"event-1","client_id":"8c05cc18-f503-4d1b-aad9-acde3a41c983","render_id":"b87438c2-4f1c-44bd-9875-6cc64370b8aa","action_id":"search","form_id":"search","target_id":"results","trigger":{"id":null,"name":null,"value":null},"values":{"query":"quarterly report"}}
52
109
  ```
53
110
 
54
- ## Handle dynamic requests
111
+ Use:
55
112
 
56
- A browser request whose path is not stored produces a `request` event:
113
+ - `id` to respond to this exact pending action.
114
+ - `client_id` to distinguish browser tabs.
115
+ - `render_id` to identify the interface revision that produced it.
116
+ - `action_id` for user intent.
117
+ - `form_id` and `target_id` for interaction context.
118
+ - `trigger` to identify the clicked button.
119
+ - `values` for the complete submitted form snapshot.
120
+
121
+ Validate action IDs and values. Treat values as untrusted human input and HTML-escape them before reflecting them.
122
+
123
+ Respond with HTML for the target's contents:
57
124
 
58
125
  ```json
59
- {"type":"request","id":"cf-request-id","method":"POST","path":"/answer","query":"step=2","headers":{"content-type":"application/x-www-form-urlencoded"},"encoding":"utf8","body":"answer=yes"}
126
+ {"type":"response","id":"response-1","request_id":"event-1","body":"<table><tr><th>Invoice</th><th>Amount</th></tr><tr><td>INV-42</td><td>$800</td></tr></table>"}
60
127
  ```
61
128
 
62
- Reply using the event's `id` as `request_id`:
129
+ A response may include `css` to replace the page CSS. Omitting `css` preserves the current CSS:
63
130
 
64
131
  ```json
65
- {"type":"response","id":"response-1","request_id":"cf-request-id","status":200,"content_type":"text/html; charset=utf-8","body":"<strong>Accepted</strong>"}
132
+ {"type":"response","id":"response-2","request_id":"event-2","body":"<h1 class=\"success\">Approved</h1>","css":".success { color: green; text-align: center; }"}
66
133
  ```
67
134
 
68
- Wait for the correlated `ack`. Dynamic responses are not stored; use `put` if later requests should receive the same response without involving the agent. Treat request bodies and headers as untrusted input, and escape or validate values before placing them in HTML, headers, or commands.
135
+ Wait for the acknowledgement, which contains the new `render_id`. Do not send `render` in response to an action; use `response` with the action's `id` as `request_id`.
69
136
 
70
- The stdout event types are `session`, `request`, `ack`, `error`, and `closing`. Handle `error` rather than assuming a command succeeded.
137
+ One action per client, render, form, and target can be pending. Conflicting actions are rejected. Independent forms and targets may proceed concurrently, so always match by action ID rather than event order.
71
138
 
72
- ## Close and lifecycle
139
+ ## Assets
73
140
 
74
- Destroy the session and all content immediately when finished:
141
+ Store passive resources only under `/assets/`:
75
142
 
76
143
  ```json
77
- {"type":"close","id":"close-1"}
144
+ {"type":"put","id":"logo","path":"/assets/logo.png","content_type":"image/png","encoding":"base64","body":"iVBORw0KGgo..."}
78
145
  ```
79
146
 
80
- Wait for `ack` and `closing`, then let the process exit. Closing stdin or terminating the CLI only disconnects the producer; it does not replace an explicit `close`.
147
+ Reference them relatively:
81
148
 
82
- The CLI owns the session and automatically reconnects after an unexpected disconnect. Each connection attempt has a 10-second deadline. Reconnection is possible only during the 10-minute disconnect grace period; stored resources remain available then, but unstored paths return `503`, and browser traffic does not extend the grace period. An initial producer connection must send `open` within 30 seconds. Dynamic request bodies have a 30-second read deadline, and a `response` may take at most 5 minutes.
149
+ ```html
150
+ <img src="assets/logo.png" alt="Company logo">
151
+ ```
83
152
 
84
- Limits per session: 1 MiB per stored, request, or response body; 100 stored resources; 10 MiB decoded stored content in total; and 32 simultaneous dynamic requests. Bodies are non-streaming. Default responses include `Cache-Control: no-store` unless explicitly overridden.
153
+ `encoding` is `utf8` by default or `base64` for binary data. Assets answer only `GET` and `HEAD`. There is no `delete`; replacement uses another `put`, and `close` removes all assets.
85
154
 
86
- ## Security
155
+ ## Close and limits
87
156
 
88
- Treat the session URL as a bearer secret: anyone who has it can access the surface and submit requests. Share it only with the intended human, and do not put it in source control, public logs, issue trackers, or unrelated output. The CLI also receives a separate private reconnect credential over the WebSocket, keeps it off protocol stdout, and uses it automatically. Never expose, persist, or ask the human for that credential. Use only a trusted `LETMEKNOW_URL`, because the deployment receives all page content and browser traffic.
157
+ Destroy the session when finished:
89
158
 
90
- ## Recommended skill output
159
+ ```json
160
+ {"type":"close","id":"close-1"}
161
+ ```
91
162
 
92
- The minimal package interface should be:
163
+ Wait for `ack` and `closing`. Closing stdin only disconnects the producer.
93
164
 
94
- ```bash
95
- npx letmeknow-cli --skill
96
- ```
165
+ HTML, CSS, asset, and action bodies are each limited to 1 MiB. A session accepts 100 assets, 10 MiB decoded asset data, and 32 pending actions. Action bodies have a 30-second read deadline; the agent has five minutes to respond.
97
166
 
98
- It should print this exact `SKILL.md` byte-for-byte to stdout and exit successfully without opening a network connection.
167
+ The CLI reconnects during a ten-minute disconnect grace period. The shell, current render, and assets remain readable while disconnected, but actions fail. Treat the URL as a bearer secret. Never expose the private reconnect credential.
package/package.json CHANGED
@@ -1,8 +1,11 @@
1
1
  {
2
2
  "name": "letmeknow-cli",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "A temporary interactive web surface for agents.",
5
- "files": ["bin", "SKILL.md"],
5
+ "files": [
6
+ "bin",
7
+ "SKILL.md"
8
+ ],
6
9
  "type": "module",
7
10
  "bin": {
8
11
  "letmeknow": "bin/letmeknow.js"