atris 3.15.13 → 3.15.22
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 +84 -8
- package/README.md +5 -1
- package/atris/AGENTS.md +46 -1
- package/atris/CLAUDE.md +36 -1
- package/atris/GEMINI.md +14 -1
- package/atris/atris.md +12 -1
- package/atris/atrisDev.md +3 -2
- package/atris/context/README.md +11 -0
- package/atris/features/company-brain-sync/validate.md +5 -5
- package/atris/learnings.jsonl +1 -0
- package/atris/policies/atris-design.md +2 -0
- package/atris/skills/aeo/SKILL.md +2 -2
- package/atris/skills/atris/SKILL.md +15 -62
- package/atris/skills/design/SKILL.md +2 -0
- package/atris/skills/imessage/SKILL.md +19 -2
- package/atris/skills/loop/SKILL.md +6 -5
- package/atris/skills/magic-inbox/SKILL.md +1 -1
- package/atris/team/_template/MEMBER.md +23 -1
- package/atris/team/brainstormer/START_HERE.md +6 -0
- package/atris/team/executor/MEMBER.md +13 -0
- package/atris/team/executor/START_HERE.md +6 -0
- package/atris/team/launcher/START_HERE.md +6 -0
- package/atris/team/mission-lead/MEMBER.md +39 -0
- package/atris/team/mission-lead/MISSION.md +33 -0
- package/atris/team/mission-lead/START_HERE.md +6 -0
- package/atris/team/navigator/MEMBER.md +11 -0
- package/atris/team/navigator/START_HERE.md +6 -0
- package/atris/team/opus-overnight/MEMBER.md +39 -0
- package/atris/team/opus-overnight/MISSION.md +61 -0
- package/atris/team/opus-overnight/START_HERE.md +6 -0
- package/atris/team/opus-overnight/STEERING.md +35 -0
- package/atris/team/researcher/START_HERE.md +6 -0
- package/atris/team/validator/MEMBER.md +26 -6
- package/atris/team/validator/START_HERE.md +6 -0
- package/atris/wiki/concepts/agent-activation-contract.md +79 -0
- package/atris/wiki/concepts/workspace-initialization-contract.md +73 -0
- package/atris/wiki/index.md +27 -0
- package/atris/wiki/sources/atris-labs-2026-05-10.txt +17 -0
- package/atris/wiki/sources/atris-labs-goals-2026-05-10.txt +15 -0
- package/atris/wiki/sources/atrisos-generative-ui-product-surface-2026-05-10.txt +10 -0
- package/atris/wiki/sources/jack-dorsey-2026-05-10.txt +12 -0
- package/atris.md +49 -13
- package/bin/atris.js +660 -22
- package/commands/activate.js +12 -3
- package/commands/aeo.js +1 -1
- package/commands/align.js +10 -10
- package/commands/analytics.js +9 -4
- package/commands/app.js +2 -0
- package/commands/apps.js +276 -0
- package/commands/auth.js +1 -1
- package/commands/autopilot.js +74 -5
- package/commands/brain.js +536 -61
- package/commands/brainstorm.js +12 -12
- package/commands/business-sync.js +142 -24
- package/commands/clean.js +9 -6
- package/commands/codex-goal.js +311 -0
- package/commands/errors.js +11 -1
- package/commands/feedback.js +55 -17
- package/commands/fork.js +2 -2
- package/commands/gm.js +376 -0
- package/commands/init.js +80 -3
- package/commands/integrations.js +524 -0
- package/commands/learn.js +25 -16
- package/commands/lesson.js +41 -0
- package/commands/lifecycle.js +2 -2
- package/commands/member.js +2416 -9
- package/commands/mission.js +1776 -0
- package/commands/now.js +48 -7
- package/commands/play.js +425 -0
- package/commands/publish.js +2 -1
- package/commands/pull.js +72 -29
- package/commands/push.js +199 -17
- package/commands/review.js +51 -13
- package/commands/skill.js +2 -2
- package/commands/soul.js +19 -13
- package/commands/status.js +6 -1
- package/commands/sync.js +5 -4
- package/commands/task.js +1041 -147
- package/commands/terminal.js +5 -5
- package/commands/verify.js +7 -5
- package/commands/visualize.js +7 -0
- package/commands/wiki.js +53 -16
- package/commands/workflow.js +298 -54
- package/commands/workspace-clean.js +1 -1
- package/commands/worktree.js +468 -0
- package/commands/xp.js +1608 -0
- package/lib/manifest.js +34 -4
- package/lib/scorecard.js +3 -2
- package/lib/task-db.js +408 -27
- package/lib/todo-fallback.js +28 -2
- package/lib/todo.js +5 -3
- package/package.json +23 -2
- package/utils/update-check.js +51 -1
package/commands/gm.js
ADDED
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const os = require('os');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
|
|
7
|
+
const ROLE_PLAYERS_TO_IGNORE = new Set([
|
|
8
|
+
'game-manager',
|
|
9
|
+
'navigator',
|
|
10
|
+
'executor',
|
|
11
|
+
'validator',
|
|
12
|
+
'launcher',
|
|
13
|
+
'researcher',
|
|
14
|
+
'brainstormer',
|
|
15
|
+
'ops',
|
|
16
|
+
]);
|
|
17
|
+
|
|
18
|
+
function showHelp() {
|
|
19
|
+
console.log('');
|
|
20
|
+
console.log('Usage: atris gm [--manager <id>] [--player <id>] [--workspace <path>] [--json]');
|
|
21
|
+
console.log('');
|
|
22
|
+
console.log('Description:');
|
|
23
|
+
console.log(' Enter AgentXP General Manager mode for the current Atris workspace.');
|
|
24
|
+
console.log(' Shows local players, active missions, review queue, and the next command');
|
|
25
|
+
console.log(' that moves the same AgentXP game loop forward.');
|
|
26
|
+
console.log('');
|
|
27
|
+
console.log('Options:');
|
|
28
|
+
console.log(' --manager <id> Manager id. Defaults to game-manager when present.');
|
|
29
|
+
console.log(' --as <id> Alias for --manager.');
|
|
30
|
+
console.log(' --player <id> Preferred player when seeding a first local mission.');
|
|
31
|
+
console.log(' --workspace <p> Read missions from another Atris workspace.');
|
|
32
|
+
console.log(' --no-seed Do not create a starter player mission.');
|
|
33
|
+
console.log(' --json Print machine-readable mode state.');
|
|
34
|
+
console.log(' --help, -h Show this help.');
|
|
35
|
+
console.log('');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function flag(args, name) {
|
|
39
|
+
const inline = args.find(arg => arg.startsWith(`${name}=`));
|
|
40
|
+
if (inline) return inline.slice(name.length + 1);
|
|
41
|
+
const index = args.indexOf(name);
|
|
42
|
+
if (index >= 0 && args[index + 1] && !args[index + 1].startsWith('--')) {
|
|
43
|
+
return args[index + 1];
|
|
44
|
+
}
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function hasFlag(args, name) {
|
|
49
|
+
return args.includes(name) || args.some(arg => arg.startsWith(`${name}=`));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function positional(args) {
|
|
53
|
+
return args.filter((arg, index) => {
|
|
54
|
+
if (arg.startsWith('--')) return false;
|
|
55
|
+
if (index > 0 && args[index - 1].startsWith('--')) return false;
|
|
56
|
+
return true;
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function slugify(value) {
|
|
61
|
+
return String(value || '')
|
|
62
|
+
.trim()
|
|
63
|
+
.toLowerCase()
|
|
64
|
+
.replace(/@.*$/, '')
|
|
65
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
66
|
+
.replace(/^-+|-+$/g, '');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function taskRef(task) {
|
|
70
|
+
return task.display_id || task.legacy_ref || String(task.id || '').slice(0, 8);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function taskAssignee(task) {
|
|
74
|
+
const metadata = task && task.metadata && typeof task.metadata === 'object'
|
|
75
|
+
? task.metadata
|
|
76
|
+
: {};
|
|
77
|
+
return metadata.assigned_to
|
|
78
|
+
|| metadata.owner
|
|
79
|
+
|| metadata.assignee
|
|
80
|
+
|| task.claimed_by
|
|
81
|
+
|| null;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function clip(value, max = 240) {
|
|
85
|
+
const text = String(value || '').replace(/\s+/g, ' ').trim();
|
|
86
|
+
if (text.length <= max) return text;
|
|
87
|
+
return `${text.slice(0, Math.max(0, max - 3)).trim()}...`;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function teamMembers(workspaceRoot) {
|
|
91
|
+
const teamDir = path.join(workspaceRoot, 'atris', 'team');
|
|
92
|
+
try {
|
|
93
|
+
return fs.readdirSync(teamDir, { withFileTypes: true })
|
|
94
|
+
.filter(entry => entry.isDirectory())
|
|
95
|
+
.map(entry => slugify(entry.name))
|
|
96
|
+
.filter(Boolean)
|
|
97
|
+
.filter(name => !name.startsWith('_') && name !== 'template')
|
|
98
|
+
.filter(name => fs.existsSync(path.join(teamDir, name, 'MEMBER.md')) || fs.existsSync(path.join(teamDir, name, 'START_HERE.md')));
|
|
99
|
+
} catch {
|
|
100
|
+
return [];
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function inferManager(workspaceRoot, args = []) {
|
|
105
|
+
const explicit = flag(args, '--manager') || flag(args, '--as') || positional(args)[0];
|
|
106
|
+
if (explicit) return { manager: slugify(explicit), source: 'flag' };
|
|
107
|
+
|
|
108
|
+
for (const value of [process.env.ATRIS_GM, process.env.ATRIS_MANAGER, process.env.ATRIS_AGENT_ID]) {
|
|
109
|
+
const manager = slugify(value);
|
|
110
|
+
if (manager) return { manager, source: 'env' };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (fs.existsSync(path.join(workspaceRoot, 'atris', 'team', 'game-manager'))) {
|
|
114
|
+
return { manager: 'game-manager', source: 'team' };
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return { manager: 'game-manager', source: 'default' };
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function activeTasks(tasks) {
|
|
121
|
+
return (tasks || []).filter(task => !['done', 'failed'].includes(task.status));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function activeAgentXpTasks(tasks) {
|
|
125
|
+
return activeTasks(tasks).filter((task) => {
|
|
126
|
+
const metadata = task.metadata || {};
|
|
127
|
+
const text = `${task.title || ''} ${task.tag || ''} ${metadata.delegate_via || ''}`.toLowerCase();
|
|
128
|
+
return text.includes('agentxp') || text.includes('agent-xp');
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function playersFromTasks(tasks) {
|
|
133
|
+
const players = new Set();
|
|
134
|
+
for (const task of activeTasks(tasks)) {
|
|
135
|
+
const assignee = slugify(taskAssignee(task));
|
|
136
|
+
if (assignee && !ROLE_PLAYERS_TO_IGNORE.has(assignee)) players.add(assignee);
|
|
137
|
+
const claimedBy = slugify(task.claimed_by);
|
|
138
|
+
if (claimedBy && !ROLE_PLAYERS_TO_IGNORE.has(claimedBy)) players.add(claimedBy);
|
|
139
|
+
}
|
|
140
|
+
return Array.from(players).sort();
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function playersFromWorkspace(workspaceRoot) {
|
|
144
|
+
return teamMembers(workspaceRoot)
|
|
145
|
+
.filter(member => !ROLE_PLAYERS_TO_IGNORE.has(member))
|
|
146
|
+
.sort();
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function starterMissionTitle() {
|
|
150
|
+
return 'AgentXP Mode first rep: complete one proof-backed customer-motion mission';
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function starterMissionPrompt(player) {
|
|
154
|
+
return [
|
|
155
|
+
`Player ${player}: enter AgentXP Mode in this local workspace.`,
|
|
156
|
+
'Pick one concrete customer-motion rep you can finish today.',
|
|
157
|
+
'Use an agent for the artifact and verifier proof.',
|
|
158
|
+
'Human accept/revise gates the XP.',
|
|
159
|
+
].join(' ');
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function pickSeedPlayer(workspaceRoot, tasks, args = []) {
|
|
163
|
+
const explicit = flag(args, '--player') || flag(args, '--user');
|
|
164
|
+
if (explicit) return slugify(explicit);
|
|
165
|
+
|
|
166
|
+
const fromTasks = playersFromTasks(tasks);
|
|
167
|
+
if (fromTasks.length === 1) return fromTasks[0];
|
|
168
|
+
|
|
169
|
+
const fromWorkspace = playersFromWorkspace(workspaceRoot);
|
|
170
|
+
if (fromWorkspace.length === 1) return fromWorkspace[0];
|
|
171
|
+
|
|
172
|
+
const local = slugify(process.env.ATRIS_PLAYER || process.env.USER || os.userInfo().username);
|
|
173
|
+
if (local && !ROLE_PLAYERS_TO_IGNORE.has(local)) return local;
|
|
174
|
+
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function ensureStarterMission(taskDb, db, workspaceRoot, tasks, args = []) {
|
|
179
|
+
if (hasFlag(args, '--no-seed')) return { tasks, seeded: null };
|
|
180
|
+
if (!fs.existsSync(path.join(workspaceRoot, 'atris'))) return { tasks, seeded: null };
|
|
181
|
+
if (activeAgentXpTasks(tasks).length) return { tasks, seeded: null };
|
|
182
|
+
|
|
183
|
+
const player = pickSeedPlayer(workspaceRoot, tasks, args);
|
|
184
|
+
if (!player) return { tasks, seeded: null };
|
|
185
|
+
|
|
186
|
+
const result = taskDb.addTask(db, {
|
|
187
|
+
title: starterMissionTitle(),
|
|
188
|
+
tag: 'agent-xp',
|
|
189
|
+
workspaceRoot,
|
|
190
|
+
metadata: {
|
|
191
|
+
assigned_to: player,
|
|
192
|
+
delegate_via: 'agentxp_gm',
|
|
193
|
+
auto_seeded_by: 'atris gm',
|
|
194
|
+
created_for_day: new Date().toISOString().slice(0, 10),
|
|
195
|
+
},
|
|
196
|
+
});
|
|
197
|
+
taskDb.noteTask(db, {
|
|
198
|
+
id: result.id,
|
|
199
|
+
actor: 'game-manager',
|
|
200
|
+
content: starterMissionPrompt(player),
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
const refreshed = taskDb.withTaskDisplayRefs(taskDb.listTasks(db, {
|
|
204
|
+
workspaceRoot,
|
|
205
|
+
limit: 500,
|
|
206
|
+
}));
|
|
207
|
+
return {
|
|
208
|
+
tasks: refreshed,
|
|
209
|
+
seeded: refreshed.find(task => task.id === result.id) || null,
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function groupPlayers(tasks, workspaceRoot) {
|
|
214
|
+
const players = new Map();
|
|
215
|
+
for (const task of activeTasks(tasks)) {
|
|
216
|
+
const player = slugify(taskAssignee(task)) || 'unassigned';
|
|
217
|
+
if (!players.has(player)) {
|
|
218
|
+
players.set(player, {
|
|
219
|
+
player,
|
|
220
|
+
source: 'task',
|
|
221
|
+
open: 0,
|
|
222
|
+
claimed: 0,
|
|
223
|
+
review: 0,
|
|
224
|
+
active: 0,
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
const row = players.get(player);
|
|
228
|
+
row.active += 1;
|
|
229
|
+
if (task.status === 'open') row.open += 1;
|
|
230
|
+
if (task.status === 'claimed') row.claimed += 1;
|
|
231
|
+
if (task.status === 'review') row.review += 1;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (!players.size) {
|
|
235
|
+
for (const player of playersFromWorkspace(workspaceRoot)) {
|
|
236
|
+
players.set(player, {
|
|
237
|
+
player,
|
|
238
|
+
source: 'team',
|
|
239
|
+
open: 0,
|
|
240
|
+
claimed: 0,
|
|
241
|
+
review: 0,
|
|
242
|
+
active: 0,
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return Array.from(players.values())
|
|
248
|
+
.filter(row => !ROLE_PLAYERS_TO_IGNORE.has(row.player))
|
|
249
|
+
.sort((a, b) => b.active - a.active || a.player.localeCompare(b.player));
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function compactTask(task) {
|
|
253
|
+
if (!task) return null;
|
|
254
|
+
return {
|
|
255
|
+
id: task.id,
|
|
256
|
+
ref: taskRef(task),
|
|
257
|
+
title: task.title,
|
|
258
|
+
status: task.status,
|
|
259
|
+
assigned_to: taskAssignee(task),
|
|
260
|
+
claimed_by: task.claimed_by || null,
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function nextCommands({ seeded, reviewQueue, missions, players }) {
|
|
265
|
+
if (reviewQueue.length) {
|
|
266
|
+
const ref = reviewQueue[0].ref;
|
|
267
|
+
return [
|
|
268
|
+
`atris task show ${ref}`,
|
|
269
|
+
`atris task accept ${ref} --proof "<human review>"`,
|
|
270
|
+
`atris task revise ${ref} --note "<what must change>"`,
|
|
271
|
+
];
|
|
272
|
+
}
|
|
273
|
+
if (missions.length) {
|
|
274
|
+
const mission = missions[0];
|
|
275
|
+
const player = mission.assigned_to || mission.claimed_by || players[0]?.player || 'player';
|
|
276
|
+
if (mission.status === 'open') return [`atris task claim ${mission.ref} --as ${player}`];
|
|
277
|
+
return [`atris play --as ${player}`];
|
|
278
|
+
}
|
|
279
|
+
if (seeded) return [`atris play --as ${seeded.assigned_to || 'player'}`];
|
|
280
|
+
return ['atris gm --player <player>'];
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function gmState(args = []) {
|
|
284
|
+
const taskDb = require('../lib/task-db');
|
|
285
|
+
const workspaceArg = flag(args, '--workspace') || flag(args, '--root') || process.cwd();
|
|
286
|
+
const workspaceRoot = taskDb.workspaceRoot(path.resolve(workspaceArg));
|
|
287
|
+
const db = taskDb.open();
|
|
288
|
+
let tasks = taskDb.withTaskDisplayRefs(taskDb.listTasks(db, {
|
|
289
|
+
workspaceRoot,
|
|
290
|
+
limit: 500,
|
|
291
|
+
}));
|
|
292
|
+
const detected = inferManager(workspaceRoot, args);
|
|
293
|
+
const starter = ensureStarterMission(taskDb, db, workspaceRoot, tasks, args);
|
|
294
|
+
tasks = starter.tasks;
|
|
295
|
+
|
|
296
|
+
const missions = activeAgentXpTasks(tasks).map(compactTask);
|
|
297
|
+
const reviewQueue = missions.filter(task => task.status === 'review');
|
|
298
|
+
const players = groupPlayers(tasks, workspaceRoot);
|
|
299
|
+
const seeded = compactTask(starter.seeded);
|
|
300
|
+
const commands = nextCommands({ seeded, reviewQueue, missions, players });
|
|
301
|
+
|
|
302
|
+
return {
|
|
303
|
+
schema: 'atris.agentxp_gm_mode.v1',
|
|
304
|
+
mode: 'AgentXP General Manager',
|
|
305
|
+
generated_at: new Date().toISOString(),
|
|
306
|
+
manager: detected.manager,
|
|
307
|
+
manager_source: detected.source,
|
|
308
|
+
workspace_root: workspaceRoot,
|
|
309
|
+
workspace_name: path.basename(workspaceRoot),
|
|
310
|
+
seeded,
|
|
311
|
+
counts: {
|
|
312
|
+
players: players.length,
|
|
313
|
+
missions: missions.length,
|
|
314
|
+
review: reviewQueue.length,
|
|
315
|
+
},
|
|
316
|
+
players,
|
|
317
|
+
missions,
|
|
318
|
+
review_queue: reviewQueue,
|
|
319
|
+
next_commands: commands,
|
|
320
|
+
xp_rule: 'GM can route missions and review proof, but AgentXP still lands only after human accept.',
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
function render(state) {
|
|
325
|
+
console.log('');
|
|
326
|
+
console.log('AgentXP General Manager');
|
|
327
|
+
console.log(`Manager ${state.manager} | Workspace ${state.workspace_name}`);
|
|
328
|
+
console.log('');
|
|
329
|
+
|
|
330
|
+
if (state.seeded) {
|
|
331
|
+
console.log(`Starter mission created locally: ${state.seeded.ref} -> ${state.seeded.assigned_to || 'player'}`);
|
|
332
|
+
console.log('');
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
console.log(`Players ${state.counts.players} | Missions ${state.counts.missions} | Review ${state.counts.review}`);
|
|
336
|
+
if (state.players.length) {
|
|
337
|
+
console.log('');
|
|
338
|
+
console.log('Players:');
|
|
339
|
+
for (const player of state.players.slice(0, 8)) {
|
|
340
|
+
console.log(`- ${player.player}: ${player.active} active, ${player.review} review`);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
if (state.missions.length) {
|
|
345
|
+
console.log('');
|
|
346
|
+
console.log('Missions:');
|
|
347
|
+
for (const task of state.missions.slice(0, 8)) {
|
|
348
|
+
console.log(`- ${task.ref} [${task.status}] ${task.assigned_to || 'unassigned'}: ${clip(task.title, 120)}`);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
console.log('');
|
|
353
|
+
console.log('XP rule: no proof, no AgentXP; accept/revise stays human-gated.');
|
|
354
|
+
console.log('');
|
|
355
|
+
console.log('Next commands:');
|
|
356
|
+
for (const command of state.next_commands) console.log(`- ${command}`);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
async function gmCommand(...args) {
|
|
360
|
+
if (args.includes('--help') || args.includes('-h') || args[0] === 'help') {
|
|
361
|
+
showHelp();
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
const state = gmState(args);
|
|
366
|
+
if (hasFlag(args, '--json')) {
|
|
367
|
+
console.log(JSON.stringify(state, null, 2));
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
render(state);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
module.exports = {
|
|
374
|
+
gmCommand,
|
|
375
|
+
gmState,
|
|
376
|
+
};
|
package/commands/init.js
CHANGED
|
@@ -233,6 +233,17 @@ ${profile.hasCode ? `**Validation:** Run \`${profile.testCommand}\` to verify ch
|
|
|
233
233
|
}
|
|
234
234
|
|
|
235
235
|
function initAtris() {
|
|
236
|
+
// Print usage on -h / --help / help instead of running init (which scaffolds
|
|
237
|
+
// many files, including atris/now.md and atris/team/). Asking for help
|
|
238
|
+
// shouldn't have file-system side effects.
|
|
239
|
+
const args = process.argv.slice(3);
|
|
240
|
+
if (args[0] === '-h' || args[0] === '--help' || args[0] === 'help') {
|
|
241
|
+
console.log('Usage: atris init [--force]');
|
|
242
|
+
console.log('');
|
|
243
|
+
console.log(' Scaffold the atris/ workspace in the current directory.');
|
|
244
|
+
console.log(' Refuses to run inside an existing atris/ folder unless --force is passed.');
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
236
247
|
// GUARD: Refuse nested init.
|
|
237
248
|
// Bug: running `atris init` inside an existing `atris/` folder creates
|
|
238
249
|
// `atris/atris/` nesting hell. Cloud doordash had this exact problem.
|
|
@@ -595,7 +606,7 @@ tools: []
|
|
|
595
606
|
// Create agent instruction files for different tools
|
|
596
607
|
const agentInstructions = `# AGENTS.md — Universal Agent Instructions
|
|
597
608
|
|
|
598
|
-
> Works with: Claude Code, Cursor, Codex, Windsurf, and any AI coding agent.
|
|
609
|
+
> Works with: Claude Code, Cursor, Codex, OpenClaw, Windsurf, and any AI coding agent.
|
|
599
610
|
|
|
600
611
|
## FIRST MESSAGE — Boot Sequence
|
|
601
612
|
|
|
@@ -609,14 +620,46 @@ This is the Atris boot sequence. Show the output to the user, then respond natur
|
|
|
609
620
|
|
|
610
621
|
## Core Files
|
|
611
622
|
|
|
623
|
+
Atris is the source of truth. This file is only an adapter for tools that read
|
|
624
|
+
\`AGENTS.md\`; do not turn it into a parallel brain. Durable policy, workflow,
|
|
625
|
+
task truth, proof, review, and backend/cloud sync all flow through Atris.
|
|
626
|
+
|
|
612
627
|
| File | Purpose |
|
|
613
628
|
|------|---------|
|
|
629
|
+
| \`atris/atris.md\` | Protocol/backbone for this workspace |
|
|
614
630
|
| \`atris/PERSONA.md\` | Communication style (read first) |
|
|
615
631
|
| \`atris task\` | Current tasks, claims, dialogue, proof |
|
|
616
632
|
| \`.atris/state/tasks.projection.json\` | Readable task projection for UIs/agents |
|
|
617
633
|
| \`atris/TODO.md\` | Rendered/legacy task view only |
|
|
618
634
|
| \`atris/MAP.md\` | Navigation (where is X?) |
|
|
619
635
|
|
|
636
|
+
## Agent Contract
|
|
637
|
+
|
|
638
|
+
Every agent should leave four artifacts another agent can trust:
|
|
639
|
+
|
|
640
|
+
| Artifact | Where |
|
|
641
|
+
|----------|-------|
|
|
642
|
+
| Objective | \`atris task note <id> "Goal / files / done / check"\` |
|
|
643
|
+
| Navigation | \`atris/MAP.md\` when a new route or file location is learned |
|
|
644
|
+
| Change | Small git diff in declared files only |
|
|
645
|
+
| Proof ready | \`atris task ready <id> --proof "<commands or receipt>"\` |
|
|
646
|
+
| Human accept | \`atris task accept <id>\` |
|
|
647
|
+
|
|
648
|
+
Do not rely on chat context. Put the task, file pointers, and proof on disk.
|
|
649
|
+
Do not write new operating doctrine here first; add it to Atris policy, skills,
|
|
650
|
+
wiki, or \`atris/atris.md\`, then regenerate this adapter if needed.
|
|
651
|
+
|
|
652
|
+
Native goals and task approval are separate gates:
|
|
653
|
+
|
|
654
|
+
\`\`\`text
|
|
655
|
+
Agent proof ready -> native goal can complete
|
|
656
|
+
Human accept -> task Done + AgentXP awarded
|
|
657
|
+
\`\`\`
|
|
658
|
+
|
|
659
|
+
Always-on agents should move proof-backed work to Review, complete their native
|
|
660
|
+
goal, then continue the mission loop with the next goal. They must not run
|
|
661
|
+
\`atris task accept\` or claim AgentXP unless a human approved the proof.
|
|
662
|
+
|
|
620
663
|
## Workflow
|
|
621
664
|
|
|
622
665
|
\`\`\`
|
|
@@ -625,6 +668,20 @@ BUILD → atris do (execute tasks)
|
|
|
625
668
|
CHECK → atris review (verify + cleanup)
|
|
626
669
|
\`\`\`
|
|
627
670
|
|
|
671
|
+
## Mission Autonomy
|
|
672
|
+
|
|
673
|
+
Use \`atris mission\` when work should survive this chat or run as an autonomous loop.
|
|
674
|
+
|
|
675
|
+
\`\`\`
|
|
676
|
+
member -> mission start --verify -> status --status active -> one bounded step -> mission tick --verify -> receipt -> complete|run|stop
|
|
677
|
+
\`\`\`
|
|
678
|
+
|
|
679
|
+
- Start current-agent work: \`atris mission start "<objective>" --owner <member> --runner codex_goal --lane code --verify "<cmd>" --stop "<condition>"\`
|
|
680
|
+
- Start headless Claude work: add \`--runner claude --cadence "15m" --always-on\`, then use \`atris mission run <id> --max-ticks 4 --complete-on-pass\`.
|
|
681
|
+
- Resume: \`atris mission status --status active --json\`, then pick the mission matching your owner/member.
|
|
682
|
+
- Prove: after one bounded step, run \`atris mission tick <id> --verify --summary "<what changed>"\`.
|
|
683
|
+
- Close: if the verifier passes, run \`atris mission complete <id> --proof "<receipt_path>"\`; if current-agent work should keep going, repeat status -> step -> tick.
|
|
684
|
+
|
|
628
685
|
## Rules
|
|
629
686
|
|
|
630
687
|
- [ ] 3-4 sentences max per response
|
|
@@ -632,8 +689,12 @@ CHECK → atris review (verify + cleanup)
|
|
|
632
689
|
- [ ] Check MAP.md before touching code
|
|
633
690
|
- [ ] Run \`atris task list\` or \`atris task next\` before picking work
|
|
634
691
|
- [ ] Claim tasks with \`atris task claim <id> --as <agent>\`
|
|
635
|
-
- [ ]
|
|
692
|
+
- [ ] Move agent-completed work to Review via \`atris task ready <id> --proof "..."\`
|
|
693
|
+
- [ ] Complete native Codex/Claude goals after proof is in Review, so always-on work can continue
|
|
694
|
+
- [ ] Only use \`atris task accept <id>\` when the human has approved the proof
|
|
695
|
+
- [ ] Keep durable learning in Atris-owned policy/skill/wiki/task state; keep \`AGENTS.md\` as a generated/pointer layer
|
|
636
696
|
- [ ] Treat \`atris/TODO.md\` as a rendered view; do not manually use it as the source of truth
|
|
697
|
+
- [ ] Use \`atris-labs\` for the Atris Labs business computer slug in docs and links
|
|
637
698
|
|
|
638
699
|
## Anti-patterns
|
|
639
700
|
|
|
@@ -670,6 +731,22 @@ CHECK → atris review (verify + cleanup)
|
|
|
670
731
|
console.log('✓ Created AGENTS.md (for Codex)');
|
|
671
732
|
}
|
|
672
733
|
|
|
734
|
+
// .devin/config.local.json for Devin for Terminal
|
|
735
|
+
const devinConfigDir = path.join(process.cwd(), '.devin');
|
|
736
|
+
const devinConfigFile = path.join(devinConfigDir, 'config.local.json');
|
|
737
|
+
if (!fs.existsSync(devinConfigFile)) {
|
|
738
|
+
fs.mkdirSync(devinConfigDir, { recursive: true });
|
|
739
|
+
const devinConfig = {
|
|
740
|
+
permissions: {
|
|
741
|
+
allow: [
|
|
742
|
+
'Exec(atris)',
|
|
743
|
+
],
|
|
744
|
+
},
|
|
745
|
+
};
|
|
746
|
+
fs.writeFileSync(devinConfigFile, `${JSON.stringify(devinConfig, null, 2)}\n`);
|
|
747
|
+
console.log('✓ Created .devin/config.local.json (for Devin)');
|
|
748
|
+
}
|
|
749
|
+
|
|
673
750
|
// .claude/commands/atris.md for Claude Code
|
|
674
751
|
const claudeCommandsDir = path.join(process.cwd(), '.claude', 'commands');
|
|
675
752
|
const claudeCommandFile = path.join(claudeCommandsDir, 'atris.md');
|
|
@@ -680,7 +757,7 @@ description: Activate Atris context - loads TODO.md, journal, and persona
|
|
|
680
757
|
allowed-tools: Read, Bash, Glob, Grep
|
|
681
758
|
---
|
|
682
759
|
|
|
683
|
-
|
|
760
|
+
Run \`atris\` and read \`atris/atris.md\`; @AGENTS.md is only a tool adapter.
|
|
684
761
|
|
|
685
762
|
Follow the workflow: plan → do → review
|
|
686
763
|
|