atris 3.26.0 → 3.28.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.
package/AGENTS.md CHANGED
@@ -110,7 +110,7 @@ member -> mission start --verify -> status --status active -> one bounded step -
110
110
  - [ ] Only use `atris task accept <id>` when the human has approved the proof
111
111
  - [ ] Keep durable learning in Atris-owned policy/skill/wiki/task state; keep `AGENTS.md` as a generated/pointer layer
112
112
  - [ ] Treat `atris/TODO.md` as a rendered view; do not manually use it as the source of truth
113
- - [ ] Use `atris-labs` for the Atris Labs business computer slug in docs and links
113
+ - [ ] Use the real business slug from local Atris state; do not hardcode private slugs in generated docs
114
114
 
115
115
  ## Anti-patterns
116
116
 
package/README.md CHANGED
@@ -10,7 +10,7 @@ Owner has many Computers
10
10
  Computer = workspace + files + tools + secrets + memory + agents + validation loop
11
11
  ```
12
12
 
13
- A computer can be personal or shared by a business. It can run a job like code, research, CRM, reporting, recruiting, event ops, support, or business ops.
13
+ A computer can be personal or shared by a business. It can run a job like code, research, CRM, reporting, event ops, support, or business ops.
14
14
 
15
15
  ## For Coding Agents
16
16
 
@@ -142,9 +142,9 @@ leaderboard.
142
142
  If you want a shared owner for a company, lab, collective, community, artist, team, or project, use the business command instead of raw `atris init`.
143
143
 
144
144
  ```bash
145
- atris business init "BLOND:ISH" --owner-email joel@blondish.world
146
- cd ~/arena/atris-business/blondish
147
- atris business onboard --website https://blondish.world --contact "Joel Zimmerman" --note "artist-led brand and ticket sales"
145
+ atris business init "Example Co" --owner-email operator@example.com
146
+ cd ~/arena/atris-business/example-co
147
+ atris business onboard --website https://example.com --contact "Example Owner" --note "sample customer workspace"
148
148
  atris align --fix
149
149
  ```
150
150
 
@@ -166,7 +166,7 @@ You can also use bare input:
166
166
  atris business onboard https://example.com "founder-led b2b ops" ./notes.md
167
167
  ```
168
168
 
169
- If you already have a folder full of source material, run it from there with `atris business init "BLOND:ISH" --here`.
169
+ If you already have a folder full of source material, run it from there with `atris business init "Example Co" --here`.
170
170
 
171
171
  When the first recap is done, record it into the RL state logs:
172
172
 
@@ -319,6 +319,8 @@ atris upgrade # Install latest from npm
319
319
  atris update # Sync local workspace files to new version
320
320
  ```
321
321
 
322
+ Packaged npm installs check for new versions during normal commands and start a background update automatically. Git checkout installs stay manual so linked development copies are not overwritten unexpectedly.
323
+
322
324
  ---
323
325
 
324
326
  **License:** MIT | **Repo:** [github.com/atrislabs/atris](https://github.com/atrislabs/atris.git)
@@ -2,9 +2,9 @@
2
2
 
3
3
  ## Current Patch
4
4
 
5
- The immediate DoorDash lane now follows the correct company-brain model:
5
+ The immediate Example Co lane now follows the correct company-brain model:
6
6
 
7
- - `atris push` keeps the business root as the path root so `doordash/atris/MAP.md` maps to cloud `/atris/MAP.md`
7
+ - `atris push` keeps the business root as the path root so `example-co/atris/MAP.md` maps to cloud `/atris/MAP.md`
8
8
  - business `pull` and `push` default to the `atris/` scope
9
9
  - root-level duplicates such as `MAP.md`, `TODO.md`, and `security-report.md` are ignored by default
10
10
  - manifests record the local workspace root to prevent a manifest from one folder authorizing pushes from another folder
@@ -114,7 +114,7 @@ Later it should also let the user ask Atris to merge semantically with model ass
114
114
 
115
115
  `atris sync --watch` is the current always-on lane:
116
116
 
117
- - watch `doordash/atris/`
117
+ - watch `example-co/atris/`
118
118
  - debounce local edits
119
119
  - fetch cloud hashes periodically
120
120
  - sync clean changes
@@ -136,5 +136,5 @@ Required before broad customer use:
136
136
  - retry-policy tests proving watch failures do not kill the alive loop
137
137
  - fixture tests proving parent-folder junk is ignored
138
138
  - fixture tests proving no cloud deletes without explicit opt-in
139
- - end-to-end dry-run against a real DoorDash-shaped workspace
139
+ - end-to-end dry-run against a real Example Co-shaped workspace
140
140
  - command copy that never recommends `--force` for normal use
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## Problem
4
4
 
5
- Atris business workspaces are company brains, not plain folders. The canonical knowledge surface is the `atris/` folder inside each business workspace, for example `doordash/atris/`.
5
+ Atris business workspaces are company brains, not plain folders. The canonical knowledge surface is the `atris/` folder inside each business workspace, for example `example-co/atris/`.
6
6
 
7
7
  Raw push/pull is the wrong abstraction for this surface. It makes a shared knowledge base feel like file mirroring, which creates merge anxiety and makes users responsible for sync safety.
8
8
 
@@ -19,7 +19,7 @@ Cloud Atris is canonical. Local Atris is a working copy. Sync publishes proposed
19
19
 
20
20
  ## User Model
21
21
 
22
- Jonathan should be able to work inside `doordash/atris/` and run one command:
22
+ Jonathan should be able to work inside `example-co/atris/` and run one command:
23
23
 
24
24
  ```bash
25
25
  atris sync
@@ -51,47 +51,47 @@ node -c commands/pull.js
51
51
  node -c commands/push.js
52
52
  ```
53
53
 
54
- Fresh DoorDash-shaped workspace dry-run:
54
+ Fresh Example Co-shaped workspace dry-run:
55
55
 
56
56
  ```bash
57
- atris sync doordash --dry-run
57
+ atris sync example-co --dry-run
58
58
  ```
59
59
 
60
60
  Observed result:
61
61
 
62
62
  ```text
63
- Syncing doordash knowledge wiki...
63
+ Syncing example-co knowledge wiki...
64
64
  scope: atris/
65
65
  ...
66
- Pushing to DoorDash...
66
+ Pushing to Example Co...
67
67
  Checking cloud freshness... fresh
68
68
  Already up to date.
69
69
  ```
70
70
 
71
- Fresh DoorDash-shaped workspace real command with no local edits:
71
+ Fresh Example Co-shaped workspace real command with no local edits:
72
72
 
73
73
  ```bash
74
- atris sync doordash
74
+ atris sync example-co
75
75
  ```
76
76
 
77
77
  Observed result:
78
78
 
79
79
  ```text
80
- Pulling DoorDash...
80
+ Pulling Example Co...
81
81
  Already up to date.
82
82
  122 unchanged.
83
- Pushing to DoorDash...
83
+ Pushing to Example Co...
84
84
  Checking cloud freshness... fresh
85
85
  Already up to date.
86
86
  ```
87
87
 
88
88
  No cloud writes were required in the validation case because the clean workspace had no local changes to publish.
89
89
 
90
- Local edit dry-run in a DoorDash-shaped workspace:
90
+ Local edit dry-run in an Example Co-shaped workspace:
91
91
 
92
92
  ```bash
93
93
  printf '# Sync smoke\n\nLocal-only knowledge update.\n' > atris/wiki/smoke/local-edit.md
94
- atris sync doordash --dry-run
94
+ atris sync example-co --dry-run
95
95
  ```
96
96
 
97
97
  Observed result:
@@ -101,11 +101,11 @@ Observed result:
101
101
  1 would be pushed, 122 unchanged. (--dry-run, nothing sent)
102
102
  ```
103
103
 
104
- Local delete dry-run in a DoorDash-shaped workspace:
104
+ Local delete dry-run in an Example Co-shaped workspace:
105
105
 
106
106
  ```bash
107
107
  rm -f atris/wiki/index.md
108
- atris sync doordash --dry-run
108
+ atris sync example-co --dry-run
109
109
  ```
110
110
 
111
111
  Observed result:
@@ -118,7 +118,7 @@ Deletes require an explicit real push with --delete.
118
118
  Real delete attempt without `--delete`:
119
119
 
120
120
  ```bash
121
- atris sync doordash
121
+ atris sync example-co
122
122
  ```
123
123
 
124
124
  Observed result:
@@ -148,10 +148,10 @@ Slug auto-detection:
148
148
  atris sync --dry-run
149
149
  ```
150
150
 
151
- Observed result from a DoorDash-shaped workspace:
151
+ Observed result from an Example Co-shaped workspace:
152
152
 
153
153
  ```text
154
- Syncing doordash knowledge wiki...
154
+ Syncing example-co knowledge wiki...
155
155
  scope: atris/
156
156
  ```
157
157
 
@@ -165,7 +165,7 @@ Observed shape:
165
165
 
166
166
  ```text
167
167
  Company brain status
168
- business: doordash
168
+ business: example-co
169
169
  brain: atris/ (...)
170
170
  conflicts: none
171
171
  watcher: ...
@@ -218,12 +218,12 @@ atris pull example-co --keep-local --only atris/wiki --timeout 120
218
218
  atris push example-co --only atris/wiki --dry-run
219
219
  ```
220
220
 
221
- - DoorDash post-publish smoke:
221
+ - Example Co post-publish smoke:
222
222
 
223
223
  ```bash
224
- cd ~/arena/atris-business/doordash
224
+ cd ~/arena/atris-business/example-co
225
225
  atris wiki verify
226
- atris push doordash --dry-run
226
+ atris push example-co --dry-run
227
227
  ```
228
228
 
229
229
  - Packaged CLI smoke already passed locally for `3.15.12`: tarball install exposes `atris pull --no-manifest` and `atris wiki verify`.
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: aeo
3
3
  description: "AI Engine Optimization — write content engineered to get cited by ChatGPT, Claude, and Gemini. Not SEO. Triggers on: aeo, AI engine, llm citation, get cited, write for ai."
4
- when_to_use: "Use when the user wants content that ranks in AI answers (not Google SERP). Examples: 'write an AEO page', 'get ExampleCo cited by ChatGPT', 'aeo for our recruiting page', 'make this quotable by LLMs'."
4
+ when_to_use: "Use when the user wants content that ranks in AI answers (not Google SERP). Examples: 'write an AEO page', 'get ExampleCo cited by ChatGPT', 'aeo for our pricing page', 'make this quotable by LLMs'."
5
5
  version: 0.1.0
6
6
  allowed-tools: Read, Write, Edit, Glob, Grep, Bash
7
7
  tags:
@@ -20,8 +20,8 @@ Every tick prints this BEFORE scanning for work, so you can see the loop's state
20
20
  ┌──────────────────────────────────────────────────────────────┐
21
21
  │ tick · 14:23 │
22
22
  │ identity: building atris-business cloud for design partners │
23
- │ horizon: wiki-from-atris-labs
24
- atris-cli wiki has 3 new pages from atris-labs
23
+ │ horizon: customer-onboarding
24
+ three setup checks are ready to ship
25
25
  │ progress: ████████░░░░ 6/9 endgame steps │
26
26
  └──────────────────────────────────────────────────────────────┘
27
27
  ```
@@ -121,7 +121,7 @@ curl -s -X POST "https://api.atris.ai/api/integrations/google-slides/presentatio
121
121
  {
122
122
  "insertText": {
123
123
  "objectId": "subtitleId",
124
- "text": "Atris Labs - Confidential"
124
+ "text": "{{company_name}} - Confidential"
125
125
  }
126
126
  }
127
127
  ]
@@ -207,7 +207,7 @@ curl -s -X POST "https://api.atris.ai/api/integrations/google-slides/presentatio
207
207
  {
208
208
  "replaceAllText": {
209
209
  "containsText": {"text": "{{company_name}}"},
210
- "replaceText": "Atris Labs"
210
+ "replaceText": "Example Co"
211
211
  }
212
212
  }
213
213
  ]
package/bin/atris.js CHANGED
@@ -92,14 +92,10 @@ if (!skipUpdateCheck && (!updateCommand || (updateCommand && !['version', 'updat
92
92
  .then((updateInfo) => {
93
93
  // Show notification if update available (after command completes)
94
94
  if (updateInfo) {
95
- // Notify only — never auto-update mid-session (opt-in via ATRIS_AUTO_UPDATE=1)
96
- if (process.env.ATRIS_AUTO_UPDATE === '1') {
97
- setTimeout(() => {
98
- if (!autoUpdate(updateInfo)) {
99
- showUpdateNotification(updateInfo);
100
- }
101
- }, 100);
102
- } else {
95
+ const autoUpdateStarted = autoUpdate(updateInfo, {
96
+ packageRoot: path.join(__dirname, '..'),
97
+ });
98
+ if (!autoUpdateStarted) {
103
99
  showUpdateNotification(updateInfo);
104
100
  }
105
101
  }
@@ -349,7 +345,7 @@ function showHelp() {
349
345
  console.log('Atris Computers:');
350
346
  console.log(' Owner = User | Business');
351
347
  console.log(' Owners have Computers: workspace + files + tools + secrets + memory + agents + validation');
352
- console.log(' Types: code, research, CRM, reporting, recruiting, events, support, business ops');
348
+ console.log(' Types: code, research, CRM, reporting, events, support, business ops');
353
349
  console.log('');
354
350
  console.log('Setup:');
355
351
  console.log(' setup - Guided first-time setup (login, pick business, pull)');
@@ -644,6 +640,7 @@ function showUpgradeHelp() {
644
640
  console.log('');
645
641
  console.log('Description:');
646
642
  console.log(' Check npm for the latest Atris CLI and install it globally if newer.');
643
+ console.log(' Normal packaged installs also auto-update in the background.');
647
644
  console.log('');
648
645
  console.log('Options:');
649
646
  console.log(' --help, -h Show this help.');
@@ -826,7 +823,7 @@ if (command === '2' && ['fast', 'pro'].includes(String(firstCommandArg || '').to
826
823
  const knownCommands = ['init', 'log', 'now', 'radar', 'ctop', 'status', 'analytics', 'visualize', 'brain', 'brainstorm', 'autopilot', 'run', 'plan', 'do', 'review', 'release',
827
824
  'activate', '_activate', 'agent', 'chat', 'fast', 'ax', 'console', 'serve', 'login', 'logout', 'whoami', 'switch', 'use', 'accounts', '_resolve', '_profile-email', '_switch-session', 'shell-init', 'update', 'upgrade', 'version', 'help', 'next', 'atris',
828
825
  'clean', 'verify', 'search', 'skill', 'member', 'codex-goal', 'app', 'apps', 'learn', 'lesson', 'plugin', 'experiments', 'receipt', 'proof', 'openclaw', 'pull', 'push', 'live', 'align', 'terminal', 'computer', 'diff', 'business', 'sync', 'youtube',
829
- 'ingest', 'query', 'lint', 'loop', 'pulse', 'task', 'mission', 'probe', 'worktree', 'aeo', 'slop', 'deck', 'site', 'theme', 'card', 'reel', 'improve', 'xp', 'play', 'gm', 'x', 'recap',
826
+ 'ingest', 'query', 'lint', 'loop', 'pulse', 'task', 'mission', 'probe', 'worktree', 'aeo', 'slop', 'security-review', 'secure', 'deck', 'site', 'theme', 'card', 'reel', 'improve', 'xp', 'play', 'gm', 'x', 'recap', 'signup', 'clarity', 'moves',
830
827
  'gmail', 'calendar', 'twitter', 'slack', 'imessage', 'integrations', 'setup', 'clean-workspace', 'cw',
831
828
  'fork', 'browse', 'publish', 'sleep', 'wake', 'feedback', 'errors', 'wiki', 'code-review', 'cr', 'soul', 'fleet', 'compile', 'spaceship'];
832
829
 
@@ -2064,6 +2061,27 @@ if (command === 'init') {
2064
2061
  Promise.resolve(require('../commands/slop').slopCommand(process.argv.slice(3)))
2065
2062
  .then((code) => process.exit(typeof code === 'number' ? code : 0))
2066
2063
  .catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
2064
+ } else if (command === 'security-review' || command === 'secure') {
2065
+ // Security review: deterministic secrets/PII/code-risk scan (no LLM). Exit 1 = HIGH finding,
2066
+ // for the autopilot/mission/CI gate + a SOC 2 evidence artifact via --json.
2067
+ Promise.resolve(require('../commands/security-review').securityReviewCommand(process.argv.slice(3)))
2068
+ .then((code) => process.exit(typeof code === 'number' ? code : 0))
2069
+ .catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
2070
+ } else if (command === 'signup') {
2071
+ // Signup: one-call seedless agent signup → writes the active profile (install→signup→play seam).
2072
+ Promise.resolve(require('../commands/signup').signupCommand(process.argv.slice(3)))
2073
+ .then((code) => process.exit(typeof code === 'number' ? code : 0))
2074
+ .catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
2075
+ } else if (command === 'moves') {
2076
+ // Moves: your 3 next moves — approve one into the loop, kill, or skip.
2077
+ Promise.resolve(require('../commands/moves').movesCommand(process.argv.slice(3)))
2078
+ .then((code) => process.exit(typeof code === 'number' ? code : 0))
2079
+ .catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
2080
+ } else if (command === 'clarity') {
2081
+ // Clarity: interview yourself once; agents read how you work so you stop repeating it.
2082
+ Promise.resolve(require('../commands/clarity').clarityCommand(process.argv.slice(3)))
2083
+ .then((code) => process.exit(typeof code === 'number' ? code : 0))
2084
+ .catch((err) => { console.error(`\n✗ Error: ${err.message || err}`); process.exit(1); });
2067
2085
  } else if (command === 'deck') {
2068
2086
  // Deck: premium Google Slides from a plain content spec, via the Atris deck engine (anti-slop design system).
2069
2087
  Promise.resolve(require('../commands/deck').run(process.argv.slice(3)))
@@ -2167,8 +2185,8 @@ async function upgradeAtris() {
2167
2185
  console.log('Installing update...');
2168
2186
  console.log('');
2169
2187
 
2170
- // Run npm update -g atris
2171
- const result = spawnSync('npm', ['update', '-g', 'atris'], {
2188
+ // Run npm install -g atris@latest
2189
+ const result = spawnSync('npm', ['install', '-g', 'atris@latest'], {
2172
2190
  stdio: 'inherit',
2173
2191
  shell: true
2174
2192
  });
@@ -2182,10 +2200,10 @@ async function upgradeAtris() {
2182
2200
  } else {
2183
2201
  console.log('');
2184
2202
  console.log('✗ Upgrade failed. Try running manually:');
2185
- console.log(' npm update -g atris');
2203
+ console.log(' npm install -g atris@latest');
2186
2204
  console.log('');
2187
2205
  console.log('If you see permission errors, try:');
2188
- console.log(' sudo npm update -g atris');
2206
+ console.log(' sudo npm install -g atris@latest');
2189
2207
  console.log('');
2190
2208
  }
2191
2209
  }
@@ -158,6 +158,30 @@ function activateAtris() {
158
158
  wikiStatus.bullets.forEach((line) => console.log(`- ${line.replace(/^- /, '')}`));
159
159
  }
160
160
  console.log('');
161
+ try {
162
+ const { nextMoves } = require('../lib/next-moves');
163
+ const { readProfile, isEmptyProfile } = require('../lib/clarity');
164
+ const root = process.cwd();
165
+ const moves = nextMoves(root, 3);
166
+ console.log('Your next moves:');
167
+ if (moves.length) {
168
+ moves.forEach((m, i) => console.log(` ${i + 1}. ${m.title}`));
169
+ console.log(' steer them: atris moves');
170
+ } else {
171
+ console.log(' none queued. add to ROADMAP.md under "## Open loop items", or jot one with atris log');
172
+ }
173
+ const profile = readProfile(root);
174
+ console.log('');
175
+ if (isEmptyProfile(profile)) {
176
+ console.log('Tip: run atris clarity once so agents learn how you work.');
177
+ } else {
178
+ console.log('How you work (atris clarity):');
179
+ ['focus', 'voice', 'cadence', 'done', 'leash']
180
+ .filter((k) => profile[k])
181
+ .forEach((k) => console.log(` ${k}: ${profile[k]}`));
182
+ }
183
+ console.log('');
184
+ } catch { /* alive onboarding is best-effort; never block activate */ }
161
185
  console.log('Next: atris plan → do → review (or atris log)');
162
186
  console.log('');
163
187
  }
package/commands/aeo.js CHANGED
@@ -173,7 +173,7 @@ function printHelp() {
173
173
  console.log('');
174
174
  console.log('Examples:');
175
175
  console.log(' atris aeo log --engine perplexity --limit 5');
176
- console.log(' atris aeo packet pallet');
176
+ console.log(' atris aeo packet <slug>');
177
177
  console.log(' atris aeo status');
178
178
  console.log(' atris aeo discover https://atris.ai/aeo --canonical-url https://atris.ai/aeo');
179
179
  }
@@ -42,7 +42,7 @@ function looksOwnerGatedTitle(title) {
42
42
  /\bhuman[- ](?:approval|input|gate|gated)\b/.test(text) ||
43
43
  /\bmanual send\b/.test(text) ||
44
44
  /\broute confirmation\b/.test(text) ||
45
- /\bconfirm pallet destination\b/.test(text) ||
45
+ /\bconfirm customer destination\b/.test(text) ||
46
46
  /\bconfirm .+ destination before .+ approval\b/.test(text) ||
47
47
  /\bapprove and manually send\b/.test(text)
48
48
  );
@@ -0,0 +1,125 @@
1
+ 'use strict';
2
+
3
+ // `atris clarity`: interview the operator for how they work, write it down once.
4
+ // The interview moves one question at a time so you stay in flow. The result is
5
+ // a durable profile (.atris/clarity.json + atris/CLARITY.md) that agents read.
6
+
7
+ const readline = require('readline');
8
+ const {
9
+ QUESTIONS,
10
+ KEYS,
11
+ mergeProfile,
12
+ isEmptyProfile,
13
+ renderClarityMd,
14
+ readProfile,
15
+ writeProfile,
16
+ profilePaths,
17
+ } = require('../lib/clarity');
18
+
19
+ function parseSets(args) {
20
+ const answers = {};
21
+ for (let i = 0; i < args.length; i++) {
22
+ if (args[i] === '--set' && args[i + 1]) {
23
+ const eq = args[i + 1].indexOf('=');
24
+ if (eq > 0) {
25
+ const key = args[i + 1].slice(0, eq).trim();
26
+ const val = args[i + 1].slice(eq + 1).trim();
27
+ if (KEYS.includes(key)) answers[key] = val;
28
+ }
29
+ i++;
30
+ }
31
+ }
32
+ return answers;
33
+ }
34
+
35
+ function ask(rl, question) {
36
+ return new Promise((resolve) => rl.question(question, (a) => resolve(a)));
37
+ }
38
+
39
+ async function clarityCommand(args = [], root = process.cwd()) {
40
+ const sub = args[0];
41
+ const stamp = new Date().toISOString();
42
+
43
+ if (args.includes('--help') || args.includes('-h') || sub === 'help') {
44
+ console.log('');
45
+ console.log('Usage: atris clarity [show|--json|--set key=value|--reset]');
46
+ console.log('');
47
+ console.log('Interview the operator for how they work, once. Agents read the result.');
48
+ console.log('');
49
+ console.log(' atris clarity Run the interview (one question at a time)');
50
+ console.log(' atris clarity show Show the current profile');
51
+ console.log(' atris clarity --json Print the profile as JSON');
52
+ console.log(' atris clarity --set voice=plain Set one field without prompting');
53
+ console.log(' atris clarity --reset Clear the profile');
54
+ console.log('');
55
+ console.log(`Fields: ${KEYS.join(', ')}`);
56
+ console.log('');
57
+ return 0;
58
+ }
59
+
60
+ if (args.includes('--reset')) {
61
+ writeProfile(root, { updated_at: stamp });
62
+ console.log('clarity profile reset.');
63
+ return 0;
64
+ }
65
+
66
+ const existing = readProfile(root);
67
+
68
+ if (args.includes('--json')) {
69
+ console.log(JSON.stringify(existing, null, 2));
70
+ return 0;
71
+ }
72
+
73
+ if (sub === 'show') {
74
+ console.log(renderClarityMd(existing));
75
+ return 0;
76
+ }
77
+
78
+ // Non-interactive set: write fields and exit.
79
+ const sets = parseSets(args);
80
+ if (Object.keys(sets).length) {
81
+ const merged = mergeProfile(existing, sets, stamp);
82
+ // Only the keys whose values actually landed (mergeProfile drops empties).
83
+ const changed = Object.keys(sets).filter((k) => sets[k].trim() && merged[k] === sets[k].trim());
84
+ if (!changed.length) {
85
+ console.log('nothing to set (empty value ignored). use --reset to clear all.');
86
+ return 0;
87
+ }
88
+ const { md } = writeProfile(root, merged);
89
+ console.log(`saved ${changed.join(', ')} to ${md.replace(`${root}/`, '')}`);
90
+ return 0;
91
+ }
92
+
93
+ // Interactive interview. Only on a terminal, so spawns never hang.
94
+ if (!process.stdin.isTTY) {
95
+ console.log(renderClarityMd(existing));
96
+ if (isEmptyProfile(existing)) {
97
+ console.log('Run `atris clarity` in a terminal to fill this in, or use --set key=value.');
98
+ }
99
+ return 0;
100
+ }
101
+
102
+ console.log('');
103
+ console.log('clarity interview. plain answers, one at a time. enter to keep the current value.');
104
+ console.log('');
105
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
106
+ const answers = {};
107
+ for (const { key, q } of QUESTIONS) {
108
+ const current = existing[key] ? ` [${existing[key]}]` : '';
109
+ // eslint-disable-next-line no-await-in-loop
110
+ const a = (await ask(rl, `${q}${current}\n> `)).trim();
111
+ if (a) answers[key] = a;
112
+ console.log('');
113
+ }
114
+ rl.close();
115
+
116
+ const merged = mergeProfile(existing, answers, stamp);
117
+ const { md } = writeProfile(root, merged);
118
+ console.log('clarity saved. agents will read it from:');
119
+ console.log(` ${md.replace(`${root}/`, '')}`);
120
+ console.log('');
121
+ console.log(renderClarityMd(merged));
122
+ return 0;
123
+ }
124
+
125
+ module.exports = { clarityCommand, parseSets };
@@ -1601,8 +1601,8 @@ async function computerCreate(token, args = [], defaults = {}) {
1601
1601
  console.log('Create a business computer, activate it, and wake it in one command.');
1602
1602
  console.log('');
1603
1603
  console.log('Examples:');
1604
- console.log(' atris computer create "My Business Computer" --business atris-labs');
1605
- console.log(' atris computer create "Recruiting Computer"');
1604
+ console.log(' atris computer create "My Business Computer" --business <business>');
1605
+ console.log(' atris computer create "Support Computer"');
1606
1606
  if (!options.name && !options.help) process.exitCode = 1;
1607
1607
  return;
1608
1608
  }
@@ -1810,8 +1810,8 @@ async function computerDelete(token, ctx, options = {}, args = []) {
1810
1810
  console.log('Sleeps the computer first, then deletes the non-default workspace after confirmation.');
1811
1811
  console.log('');
1812
1812
  console.log('Examples:');
1813
- console.log(' atris computer delete --business atris-labs --workspace ws_123');
1814
- console.log(' atris computer delete --business atris-labs --workspace ws_123 --confirm "delete ws_123"');
1813
+ console.log(' atris computer delete --business <business> --workspace ws_123');
1814
+ console.log(' atris computer delete --business <business> --workspace ws_123 --confirm "delete ws_123"');
1815
1815
  return;
1816
1816
  }
1817
1817
 
@@ -3291,7 +3291,7 @@ async function runComputer() {
3291
3291
  console.log(' Owner has many Computers');
3292
3292
  console.log(' Computer = workspace + files + tools + secrets + memory + agents + validation');
3293
3293
  console.log('');
3294
- console.log('Common types: codeops, research, CRM, reporting, recruiting, event ops, support, business ops.');
3294
+ console.log('Common types: codeops, research, CRM, reporting, event ops, support, business ops.');
3295
3295
  console.log('A business can be a company, lab, collective, community, artist, team, or project.');
3296
3296
  console.log('');
3297
3297
  console.log('First use:');
@@ -3342,10 +3342,10 @@ async function runComputer() {
3342
3342
  console.log(' atris computer');
3343
3343
  console.log(' atris computer card --write');
3344
3344
  console.log(' atris business init "My Lab" # first/default computer with Atris + operator');
3345
- console.log(' atris computer create "Recruiting Computer" --business atris-labs');
3346
- console.log(' atris computer --business atris-labs --workspace <workspace-id>');
3347
- console.log(' atris computer sleep --business atris-labs --workspace <workspace-id>');
3348
- console.log(' atris computer delete --business atris-labs --workspace <workspace-id>');
3345
+ console.log(' atris computer create "Support Computer" --business <business>');
3346
+ console.log(' atris computer --business <business> --workspace <workspace-id>');
3347
+ console.log(' atris computer sleep --business <business> --workspace <workspace-id>');
3348
+ console.log(' atris computer delete --business <business> --workspace <workspace-id>');
3349
3349
  console.log(' atris computer proof');
3350
3350
  console.log(' atris computer local');
3351
3351
  console.log(' atris computer codex');
@@ -231,7 +231,7 @@ function printHelp(write = console.log) {
231
231
  write(' atris feedback delete <id> Delete feedback (admin)');
232
232
  write('');
233
233
  write('IDs may be the first 8 chars of the UUID.');
234
- write('Business slugs come from ~/.atris/businesses.json (e.g. acme, atris-labs).');
234
+ write('Business slugs come from ~/.atris/businesses.json.');
235
235
  write('');
236
236
  }
237
237
 
package/commands/init.js CHANGED
@@ -257,7 +257,7 @@ function initAtris() {
257
257
  }
258
258
  // GUARD: Refuse nested init.
259
259
  // Bug: running `atris init` inside an existing `atris/` folder creates
260
- // `atris/atris/` nesting hell. Cloud doordash had this exact problem.
260
+ // `atris/atris/` nesting hell. A cloud business workspace had this exact problem.
261
261
  // Fix: detect three nesting conditions and refuse with a clear error.
262
262
  const cwd = process.cwd();
263
263
  const cwdBase = path.basename(cwd);
@@ -705,7 +705,7 @@ member -> mission start --verify -> status --status active -> one bounded step -
705
705
  - [ ] Only use \`atris task accept <id>\` when the human has approved the proof
706
706
  - [ ] Keep durable learning in Atris-owned policy/skill/wiki/task state; keep \`AGENTS.md\` as a generated/pointer layer
707
707
  - [ ] Treat \`atris/TODO.md\` as a rendered view; do not manually use it as the source of truth
708
- - [ ] Use \`atris-labs\` for the Atris Labs business computer slug in docs and links
708
+ - [ ] Use the real business slug from local Atris state; do not hardcode private slugs in generated docs
709
709
 
710
710
  ## Anti-patterns
711
711
 
package/commands/live.js CHANGED
@@ -101,10 +101,10 @@ function printLiveHelp() {
101
101
  console.log('Keeps a business brain fresh: doctor, pull, watch local changes, push after quiet, and periodically pull.');
102
102
  console.log('');
103
103
  console.log('Examples:');
104
- console.log(' atris live atris-labs');
104
+ console.log(' atris live <business>');
105
105
  console.log(' atris live --once');
106
- console.log(' atris live atris-labs --dry-run');
107
- console.log(' atris live atris-labs --interval=120 --debounce=30');
106
+ console.log(' atris live <business> --dry-run');
107
+ console.log(' atris live <business> --interval=120 --debounce=30');
108
108
  console.log('');
109
109
  console.log('Options:');
110
110
  console.log(' --once Run one freshness cycle and exit');