@empirical-gauzza/cli 1.0.25 → 1.0.27

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.
package/README.md CHANGED
@@ -1,63 +1,63 @@
1
- # @empirical-gauzza/cli
2
-
3
- Command-line installer and local MCP wiring helper for [Empirical](https://empirical.gauzza.com) — portable memory infrastructure for AI agents, assistants, and coding tools.
4
-
5
- Full documentation: **[empirical.gauzza.com/docs/cli-details](https://empirical.gauzza.com/docs/cli-details)**
6
-
7
- ## Install
8
-
9
- ```bash
10
- npm install -g @empirical-gauzza/cli
11
- ```
12
-
13
- ## Quick start
14
-
15
- ```bash
16
- empirical install # interactive setup for Claude Code, Codex, or Copilot CLI
17
- empirical auth login # browser-based OAuth login
18
- empirical doctor # verify token, API connectivity, and workspace status
19
- ```
20
-
21
- Full walkthrough: [empirical.gauzza.com/docs/install](https://empirical.gauzza.com/docs/install)
22
-
23
- ## What it does
24
-
25
- - Installs and configures the Empirical MCP plugin for supported coding agents (Claude Code, Codex CLI, Copilot CLI)
26
- - Manages OAuth login, including headless/CI bootstrap and Docker token flows
27
- - Reads, writes, and maintains memories from the command line
28
- - Manages Skills Kits — create, sync, and push authored Skills across machines
29
- - Manages workspaces, invites, and registered devices
30
- - Exposes agent-readable docs and a connectivity `doctor` check
31
-
32
- ## Commands
33
-
34
- | Command | Docs |
35
- | --- | --- |
36
- | `empirical install` | [/docs/install](https://empirical.gauzza.com/docs/install#connect) |
37
- | `empirical plugin install / check` | [/docs/cli-plugins](https://empirical.gauzza.com/docs/cli-plugins) |
38
- | `empirical auth login / logout` | [/docs/cli-auth](https://empirical.gauzza.com/docs/cli-auth) |
39
- | `empirical oauth bootstrap / refresh` | [/docs/cli-oauth](https://empirical.gauzza.com/docs/cli-oauth) |
40
- | `empirical policy show / set` | [/docs/cli-policy](https://empirical.gauzza.com/docs/cli-policy) |
41
- | `empirical memory query / record / update / delete / export ...` | [/docs/cli-memory](https://empirical.gauzza.com/docs/cli-memory) |
42
- | `empirical workspace list / create / invite ...` | [/docs/cli-workspaces](https://empirical.gauzza.com/docs/cli-workspaces) |
43
- | `empirical kit create / sync / use ...` | [/docs/cli-kit](https://empirical.gauzza.com/docs/cli-kit) |
44
- | `empirical skill push / history / rollback` | [/docs/cli-skill](https://empirical.gauzza.com/docs/cli-skill) |
45
- | `empirical device list / show` | [/docs/cli-devices](https://empirical.gauzza.com/docs/cli-devices) |
46
- | `empirical doc [topic]` | [/docs/cli-doc-command](https://empirical.gauzza.com/docs/cli-doc-command) |
47
- | `empirical doctor` | [/docs/cli-doctor](https://empirical.gauzza.com/docs/cli-doctor) |
48
-
49
- Run `empirical --help` at any time for the full, current command list, or `empirical doc` for agent-readable topic docs.
50
-
51
- ## Security model
52
-
53
- API keys and OAuth tokens are stored locally and are never printed in full after initial issuance. See [empirical.gauzza.com/docs/security-model](https://empirical.gauzza.com/docs/security-model) for details on credential handling and headless/CI usage.
54
-
55
- ## Links
56
-
57
- - [Documentation](https://empirical.gauzza.com/docs/install)
58
- - [Homepage](https://empirical.gauzza.com)
59
- - [Support](https://empirical.gauzza.com/support/)
60
-
61
- ## License
62
-
63
- MIT
1
+ # @empirical-gauzza/cli
2
+
3
+ Command-line installer and local MCP wiring helper for [Empirical](https://empirical.gauzza.com) — portable memory infrastructure for AI agents, assistants, and coding tools.
4
+
5
+ Full documentation: **[empirical.gauzza.com/docs/cli-details](https://empirical.gauzza.com/docs/cli-details)**
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install -g @empirical-gauzza/cli
11
+ ```
12
+
13
+ ## Quick start
14
+
15
+ ```bash
16
+ empirical install # interactive setup for Claude Code, Codex, or Copilot CLI
17
+ empirical auth login # browser-based OAuth login
18
+ empirical doctor # verify token, API connectivity, and workspace status
19
+ ```
20
+
21
+ Full walkthrough: [empirical.gauzza.com/docs/install](https://empirical.gauzza.com/docs/install)
22
+
23
+ ## What it does
24
+
25
+ - Installs and configures the Empirical MCP plugin for supported coding agents (Claude Code, Codex CLI, Copilot CLI)
26
+ - Manages OAuth login, including headless/CI bootstrap and Docker token flows
27
+ - Reads, writes, and maintains memories from the command line
28
+ - Manages Skills Kits — create, sync, and push authored Skills across machines
29
+ - Manages workspaces, invites, and registered devices
30
+ - Exposes agent-readable docs and a connectivity `doctor` check
31
+
32
+ ## Commands
33
+
34
+ | Command | Docs |
35
+ | --- | --- |
36
+ | `empirical install` | [/docs/install](https://empirical.gauzza.com/docs/install#connect) |
37
+ | `empirical plugin install / check` | [/docs/cli-plugins](https://empirical.gauzza.com/docs/cli-plugins) |
38
+ | `empirical auth login / logout` | [/docs/cli-auth](https://empirical.gauzza.com/docs/cli-auth) |
39
+ | `empirical oauth bootstrap / refresh` | [/docs/cli-oauth](https://empirical.gauzza.com/docs/cli-oauth) |
40
+ | `empirical policy show / set` | [/docs/cli-policy](https://empirical.gauzza.com/docs/cli-policy) |
41
+ | `empirical memory query / record / update / delete / export ...` | [/docs/cli-memory](https://empirical.gauzza.com/docs/cli-memory) |
42
+ | `empirical workspace list / create / invite ...` | [/docs/cli-workspaces](https://empirical.gauzza.com/docs/cli-workspaces) |
43
+ | `empirical kit create / sync / use ...` | [/docs/cli-kit](https://empirical.gauzza.com/docs/cli-kit) |
44
+ | `empirical skill push / history / rollback` | [/docs/cli-skill](https://empirical.gauzza.com/docs/cli-skill) |
45
+ | `empirical device list / show` | [/docs/cli-devices](https://empirical.gauzza.com/docs/cli-devices) |
46
+ | `empirical doc [topic]` | [/docs/cli-doc-command](https://empirical.gauzza.com/docs/cli-doc-command) |
47
+ | `empirical doctor` | [/docs/cli-doctor](https://empirical.gauzza.com/docs/cli-doctor) |
48
+
49
+ Run `empirical --help` at any time for the full, current command list, or `empirical doc` for agent-readable topic docs.
50
+
51
+ ## Security model
52
+
53
+ API keys and OAuth tokens are stored locally and are never printed in full after initial issuance. See [empirical.gauzza.com/docs/security-model](https://empirical.gauzza.com/docs/security-model) for details on credential handling and headless/CI usage.
54
+
55
+ ## Links
56
+
57
+ - [Documentation](https://empirical.gauzza.com/docs/install)
58
+ - [Homepage](https://empirical.gauzza.com)
59
+ - [Support](https://empirical.gauzza.com/support/)
60
+
61
+ ## License
62
+
63
+ MIT
package/lib/constants.js CHANGED
@@ -58,7 +58,12 @@ Flags:
58
58
  ### record
59
59
  Save a new memory.
60
60
 
61
- empirical memory record --category build --summary "Use ESM modules for all new packages" [--tags ts,node] [--node-type observation]
61
+ empirical memory record --category build --summary "Use ESM modules for all new packages" [--tags ts,node] [--node-type observation] [--author-type user|agent]
62
+
63
+ \`--author-type\` records WHO the fact belongs to, which the transport cannot know. Use
64
+ \`user\` for something the user said, decided or prefers; \`agent\` for your own session notes
65
+ and findings. Omitted, it is left unresolved rather than guessed. Retrieval reads it to keep
66
+ agent notes out of answers about the user's own life and work.
62
67
 
63
68
  Passing text that contains code (backticks, \${...}, $(...)): do NOT put it in a double-quoted
64
69
  \`--summary "..."\` -- the shell substitutes those away before the CLI runs and the write still
package/lib/doc.js CHANGED
@@ -11,7 +11,7 @@ function runDoc(args) {
11
11
  user: 'Get current user identity (MCP: get_user; CLI: doctor --output json)',
12
12
  workspace: 'List, view, and switch workspaces',
13
13
  doctor: 'Check token, connectivity, and workspace health',
14
- agents: 'Supported agents, integration modes, and native plugin setup',
14
+ agents: 'Supported agents, integration modes, and native plugin setup',
15
15
  auth: 'Token types, bootstrap, refresh, resolution order',
16
16
  install: 'Install Empirical for Codex / Copilot / Claude Code',
17
17
  kit: 'Create, source, activate, and sync Skills Kits',
package/lib/env.js CHANGED
@@ -1,49 +1,49 @@
1
- 'use strict';
2
-
3
- const { ask } = require('./ui');
4
-
5
- function getEnv(name, fallback = '') {
6
- return String(process.env[name] ?? fallback).trim();
7
- }
8
-
9
- function requireEnv(name) {
10
- const value = getEnv(name);
11
- if (!value) {
12
- throw new Error(`Missing required env var: ${name}`);
13
- }
14
- return value;
15
- }
16
-
17
- async function resolveRequiredValueFromEnvOrPrompt(envName, promptLabel) {
18
- const value = getEnv(envName);
19
- if (value) return value;
20
-
21
- if (!process.stdin.isTTY) {
22
- throw new Error(`Missing required env var: ${envName}`);
23
- }
24
-
25
- const answer = (await ask(`${promptLabel}: `)).trim();
26
- if (!answer) {
27
- throw new Error(`${promptLabel} is required`);
28
- }
29
-
30
- return answer;
31
- }
32
-
33
- function parseFlag(args, flagName) {
34
- return args.includes(flagName);
35
- }
36
-
37
- function parseOption(args, optionName, fallback = '') {
38
- const index = args.indexOf(optionName);
39
- if (index === -1) return fallback;
40
- return String(args[index + 1] || '').trim() || fallback;
41
- }
42
-
43
- module.exports = {
44
- getEnv,
45
- requireEnv,
46
- resolveRequiredValueFromEnvOrPrompt,
47
- parseFlag,
48
- parseOption
49
- };
1
+ 'use strict';
2
+
3
+ const { ask } = require('./ui');
4
+
5
+ function getEnv(name, fallback = '') {
6
+ return String(process.env[name] ?? fallback).trim();
7
+ }
8
+
9
+ function requireEnv(name) {
10
+ const value = getEnv(name);
11
+ if (!value) {
12
+ throw new Error(`Missing required env var: ${name}`);
13
+ }
14
+ return value;
15
+ }
16
+
17
+ async function resolveRequiredValueFromEnvOrPrompt(envName, promptLabel) {
18
+ const value = getEnv(envName);
19
+ if (value) return value;
20
+
21
+ if (!process.stdin.isTTY) {
22
+ throw new Error(`Missing required env var: ${envName}`);
23
+ }
24
+
25
+ const answer = (await ask(`${promptLabel}: `)).trim();
26
+ if (!answer) {
27
+ throw new Error(`${promptLabel} is required`);
28
+ }
29
+
30
+ return answer;
31
+ }
32
+
33
+ function parseFlag(args, flagName) {
34
+ return args.includes(flagName);
35
+ }
36
+
37
+ function parseOption(args, optionName, fallback = '') {
38
+ const index = args.indexOf(optionName);
39
+ if (index === -1) return fallback;
40
+ return String(args[index + 1] || '').trim() || fallback;
41
+ }
42
+
43
+ module.exports = {
44
+ getEnv,
45
+ requireEnv,
46
+ resolveRequiredValueFromEnvOrPrompt,
47
+ parseFlag,
48
+ parseOption
49
+ };
package/lib/http.js CHANGED
@@ -1,179 +1,187 @@
1
- 'use strict';
2
-
3
- const http = require('http');
4
- const https = require('https');
5
- const { warn } = require('./ui');
6
-
7
- function httpGet(urlString, timeoutMs = 8000) {
8
- return new Promise((resolve, reject) => {
9
- const parsed = new URL(urlString);
10
- const lib = parsed.protocol === 'https:' ? https : http;
11
- const req = lib.request(
12
- parsed,
13
- {
14
- method: 'GET',
15
- headers: {
16
- 'User-Agent': 'empirical-installer/1.0'
17
- }
18
- },
19
- (res) => {
20
- let body = '';
21
- res.setEncoding('utf8');
22
- res.on('data', (chunk) => {
23
- body += chunk;
24
- });
25
- res.on('end', () => {
26
- resolve({
27
- statusCode: res.statusCode || 0,
28
- headers: res.headers || {},
29
- body
30
- });
31
- });
32
- }
33
- );
34
-
35
- req.setTimeout(timeoutMs, () => {
36
- req.destroy(new Error('request timeout'));
37
- });
38
- req.on('error', reject);
39
- req.end();
40
- });
41
- }
42
-
43
- function httpErrorFromResponse(method, urlString, statusCode, data) {
44
- const baseMsg = data.error_description || data.message || data.error || `HTTP ${statusCode}`;
45
- const upgradeUrl = data.upgrade_url || data.details?.upgradeUrl || null;
46
- const retryAfterSeconds = data.retry_after_seconds ?? null;
47
-
48
- const parts = [`${method} ${urlString} failed: ${baseMsg}`];
49
- if (retryAfterSeconds != null) parts.push(`Retry after ${retryAfterSeconds}s.`);
50
- if (upgradeUrl) parts.push(`Upgrade: ${upgradeUrl}`);
51
-
52
- const error = new Error(parts.join(' '));
53
- error.statusCode = statusCode;
54
- error.code = data.code || null;
55
- error.upgradeUrl = upgradeUrl;
56
- error.retryAfterSeconds = retryAfterSeconds;
57
- return error;
58
- }
59
-
60
- // Prints a structured JSON error line to stderr so scripts/agents parsing CLI
61
- // output can branch on `code` (e.g. RATE_LIMITED, PLAN_LIMIT_MEMORY_REACHED)
62
- // and act on `upgradeUrl`/`retryAfterSeconds` without string-parsing `message`.
63
- function printApiError(error) {
64
- warn(JSON.stringify({
65
- error: true,
66
- code: error.code || 'api_error',
67
- message: error.message,
68
- ...(error.retryAfterSeconds != null && { retryAfterSeconds: error.retryAfterSeconds }),
69
- ...(error.upgradeUrl && { upgradeUrl: error.upgradeUrl })
70
- }));
71
- }
72
-
73
- function httpJson(urlString, method, payload, headers = {}, timeoutMs = 0) {
74
- return new Promise((resolve, reject) => {
75
- const parsed = new URL(urlString);
76
- const lib = parsed.protocol === 'https:' ? https : http;
77
- const body = payload ? JSON.stringify(payload) : null;
78
-
79
- const req = lib.request(
80
- parsed,
81
- {
82
- method,
83
- headers: {
84
- Accept: 'application/json',
85
- ...(body ? { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(body) } : {}),
86
- ...headers
87
- }
88
- },
89
- (res) => {
90
- let raw = '';
91
- res.setEncoding('utf8');
92
- res.on('data', (chunk) => {
93
- raw += chunk;
94
- });
95
- res.on('end', () => {
96
- let data = {};
97
- try {
98
- data = raw ? JSON.parse(raw) : {};
99
- } catch (_error) {
100
- data = { raw };
101
- }
102
-
103
- const statusCode = res.statusCode || 0;
104
- if (statusCode < 200 || statusCode >= 300) {
105
- reject(httpErrorFromResponse(method, urlString, statusCode, data));
106
- return;
107
- }
108
-
109
- resolve(data);
110
- });
111
- }
112
- );
113
-
114
- req.on('error', reject);
115
- if (Number.isFinite(timeoutMs) && timeoutMs > 0) {
116
- req.setTimeout(timeoutMs, () => {
117
- req.destroy(new Error(`request timeout after ${timeoutMs}ms`));
118
- });
119
- }
120
- if (body) req.write(body);
121
- req.end();
122
- });
123
- }
124
-
125
- function httpForm(urlString, method, params, headers = {}) {
126
- return new Promise((resolve, reject) => {
127
- const parsed = new URL(urlString);
128
- const lib = parsed.protocol === 'https:' ? https : http;
129
- const body = new URLSearchParams(params).toString();
130
-
131
- const req = lib.request(
132
- parsed,
133
- {
134
- method,
135
- headers: {
136
- Accept: 'application/json',
137
- 'Content-Type': 'application/x-www-form-urlencoded',
138
- 'Content-Length': Buffer.byteLength(body),
139
- ...headers
140
- }
141
- },
142
- (res) => {
143
- let raw = '';
144
- res.setEncoding('utf8');
145
- res.on('data', (chunk) => {
146
- raw += chunk;
147
- });
148
- res.on('end', () => {
149
- let data = {};
150
- try {
151
- data = raw ? JSON.parse(raw) : {};
152
- } catch (_error) {
153
- data = { raw };
154
- }
155
-
156
- const statusCode = res.statusCode || 0;
157
- if (statusCode < 200 || statusCode >= 300) {
158
- reject(httpErrorFromResponse(method, urlString, statusCode, data));
159
- return;
160
- }
161
-
162
- resolve(data);
163
- });
164
- }
165
- );
166
-
167
- req.on('error', reject);
168
- req.write(body);
169
- req.end();
170
- });
171
- }
172
-
173
- module.exports = {
174
- httpGet,
175
- httpErrorFromResponse,
176
- printApiError,
177
- httpJson,
178
- httpForm
179
- };
1
+ 'use strict';
2
+
3
+ const http = require('http');
4
+ const https = require('https');
5
+ const { warn } = require('./ui');
6
+
7
+ function httpGet(urlString, timeoutMs = 8000) {
8
+ return new Promise((resolve, reject) => {
9
+ const parsed = new URL(urlString);
10
+ const lib = parsed.protocol === 'https:' ? https : http;
11
+ const req = lib.request(
12
+ parsed,
13
+ {
14
+ method: 'GET',
15
+ headers: {
16
+ 'User-Agent': 'empirical-cli/1.0'
17
+ }
18
+ },
19
+ (res) => {
20
+ let body = '';
21
+ res.setEncoding('utf8');
22
+ res.on('data', (chunk) => {
23
+ body += chunk;
24
+ });
25
+ res.on('end', () => {
26
+ resolve({
27
+ statusCode: res.statusCode || 0,
28
+ headers: res.headers || {},
29
+ body
30
+ });
31
+ });
32
+ }
33
+ );
34
+
35
+ req.setTimeout(timeoutMs, () => {
36
+ req.destroy(new Error('request timeout'));
37
+ });
38
+ req.on('error', reject);
39
+ req.end();
40
+ });
41
+ }
42
+
43
+ function httpErrorFromResponse(method, urlString, statusCode, data) {
44
+ const baseMsg = data.error_description || data.message || data.error || `HTTP ${statusCode}`;
45
+ const upgradeUrl = data.upgrade_url || data.details?.upgradeUrl || null;
46
+ const retryAfterSeconds = data.retry_after_seconds ?? null;
47
+
48
+ const parts = [`${method} ${urlString} failed: ${baseMsg}`];
49
+ if (retryAfterSeconds != null) parts.push(`Retry after ${retryAfterSeconds}s.`);
50
+ if (upgradeUrl) parts.push(`Upgrade: ${upgradeUrl}`);
51
+
52
+ const error = new Error(parts.join(' '));
53
+ error.statusCode = statusCode;
54
+ error.code = data.code || null;
55
+ error.upgradeUrl = upgradeUrl;
56
+ error.retryAfterSeconds = retryAfterSeconds;
57
+ return error;
58
+ }
59
+
60
+ // Prints a structured JSON error line to stderr so scripts/agents parsing CLI
61
+ // output can branch on `code` (e.g. RATE_LIMITED, PLAN_LIMIT_MEMORY_REACHED)
62
+ // and act on `upgradeUrl`/`retryAfterSeconds` without string-parsing `message`.
63
+ function printApiError(error) {
64
+ warn(JSON.stringify({
65
+ error: true,
66
+ code: error.code || 'api_error',
67
+ message: error.message,
68
+ ...(error.retryAfterSeconds != null && { retryAfterSeconds: error.retryAfterSeconds }),
69
+ ...(error.upgradeUrl && { upgradeUrl: error.upgradeUrl })
70
+ }));
71
+ }
72
+
73
+ function httpJson(urlString, method, payload, headers = {}, timeoutMs = 0) {
74
+ return new Promise((resolve, reject) => {
75
+ const parsed = new URL(urlString);
76
+ const lib = parsed.protocol === 'https:' ? https : http;
77
+ const body = payload ? JSON.stringify(payload) : null;
78
+
79
+ const req = lib.request(
80
+ parsed,
81
+ {
82
+ method,
83
+ headers: {
84
+ Accept: 'application/json',
85
+ // Identifies the client so the server can tell a CLI write from a portal write
86
+ // (services/memoryAuthorship.ts). Writes also send source: 'cli' in the body,
87
+ // which is authoritative; this covers every other endpoint.
88
+ 'User-Agent': 'empirical-cli/1.0',
89
+ ...(body ? { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(body) } : {}),
90
+ ...headers
91
+ }
92
+ },
93
+ (res) => {
94
+ let raw = '';
95
+ res.setEncoding('utf8');
96
+ res.on('data', (chunk) => {
97
+ raw += chunk;
98
+ });
99
+ res.on('end', () => {
100
+ let data = {};
101
+ try {
102
+ data = raw ? JSON.parse(raw) : {};
103
+ } catch (_error) {
104
+ data = { raw };
105
+ }
106
+
107
+ const statusCode = res.statusCode || 0;
108
+ if (statusCode < 200 || statusCode >= 300) {
109
+ reject(httpErrorFromResponse(method, urlString, statusCode, data));
110
+ return;
111
+ }
112
+
113
+ resolve(data);
114
+ });
115
+ }
116
+ );
117
+
118
+ req.on('error', reject);
119
+ if (Number.isFinite(timeoutMs) && timeoutMs > 0) {
120
+ req.setTimeout(timeoutMs, () => {
121
+ req.destroy(new Error(`request timeout after ${timeoutMs}ms`));
122
+ });
123
+ }
124
+ if (body) req.write(body);
125
+ req.end();
126
+ });
127
+ }
128
+
129
+ function httpForm(urlString, method, params, headers = {}) {
130
+ return new Promise((resolve, reject) => {
131
+ const parsed = new URL(urlString);
132
+ const lib = parsed.protocol === 'https:' ? https : http;
133
+ const body = new URLSearchParams(params).toString();
134
+
135
+ const req = lib.request(
136
+ parsed,
137
+ {
138
+ method,
139
+ headers: {
140
+ Accept: 'application/json',
141
+ // Identifies the client so the server can tell a CLI write from a portal write
142
+ // (services/memoryAuthorship.ts). Writes also send source: 'cli' in the body,
143
+ // which is authoritative; this covers every other endpoint.
144
+ 'User-Agent': 'empirical-cli/1.0',
145
+ 'Content-Type': 'application/x-www-form-urlencoded',
146
+ 'Content-Length': Buffer.byteLength(body),
147
+ ...headers
148
+ }
149
+ },
150
+ (res) => {
151
+ let raw = '';
152
+ res.setEncoding('utf8');
153
+ res.on('data', (chunk) => {
154
+ raw += chunk;
155
+ });
156
+ res.on('end', () => {
157
+ let data = {};
158
+ try {
159
+ data = raw ? JSON.parse(raw) : {};
160
+ } catch (_error) {
161
+ data = { raw };
162
+ }
163
+
164
+ const statusCode = res.statusCode || 0;
165
+ if (statusCode < 200 || statusCode >= 300) {
166
+ reject(httpErrorFromResponse(method, urlString, statusCode, data));
167
+ return;
168
+ }
169
+
170
+ resolve(data);
171
+ });
172
+ }
173
+ );
174
+
175
+ req.on('error', reject);
176
+ req.write(body);
177
+ req.end();
178
+ });
179
+ }
180
+
181
+ module.exports = {
182
+ httpGet,
183
+ httpErrorFromResponse,
184
+ printApiError,
185
+ httpJson,
186
+ httpForm
187
+ };
@@ -51,6 +51,11 @@ picking up previously completed work), query Empirical first - do not assume you
51
51
  enough context. After completing meaningful work, or discovering a mistake worth not repeating,
52
52
  record it in Empirical, not in a local file.
53
53
 
54
+ When you record, say who authored the fact: \`authorType: "user"\` for something the user said,
55
+ decided or prefers, \`"agent"\` for your own work and findings. Nothing infers this - not the
56
+ transport, not the client - so an omitted value stays unknown forever, and a wrong one puts your
57
+ session notes into answers about the user's own life.
58
+
54
59
  Installed Empirical skills in this environment:
55
60
  ${skillLines}
56
61