atris 3.58.7 → 3.59.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 +3 -2
- package/GETTING_STARTED.md +2 -2
- package/PERSONA.md +11 -11
- package/README.md +1 -1
- package/atris/GEMINI.md +7 -6
- package/atris/PERSONA.md +4 -4
- package/atris/features/README.md +77 -6
- package/atris/skills/README.md +44 -15
- package/atris/skills/aeo/SKILL.md +10 -10
- package/atris/skills/atris/SKILL.md +1 -1
- package/atris/skills/engines/SKILL.md +69 -50
- package/atris/skills/meta/SKILL.md +4 -4
- package/bin/atris.js +8 -6
- package/commands/aeo.js +9 -12
- package/commands/analytics.js +8 -11
- package/commands/autopilot.js +79 -8
- package/commands/avail.js +1 -1
- package/commands/brain.js +3 -1
- package/commands/business.js +13 -8
- package/commands/clean.js +17 -0
- package/commands/close.js +2 -1
- package/commands/computer.js +15 -10
- package/commands/context-sync.js +3 -3
- package/commands/doc-health.js +55 -2
- package/commands/engine.js +384 -4
- package/commands/experiments.js +13 -4
- package/commands/host.js +53 -0
- package/commands/improve.js +1 -1
- package/commands/integrations.js +2 -5
- package/commands/learn.js +1 -1
- package/commands/member.js +231 -53
- package/commands/mission.js +129 -19
- package/commands/one-lap.js +58 -3
- package/commands/pack.js +2 -2
- package/commands/probe.js +11 -5
- package/commands/pull.js +1 -1
- package/commands/push.js +1 -1
- package/commands/rainmaker.js +3 -16
- package/commands/run.js +4 -1
- package/commands/scout.js +1 -1
- package/commands/search.js +5 -3
- package/commands/spaceship.js +1 -1
- package/commands/stream.js +27 -2
- package/commands/study.js +15 -9
- package/commands/sync.js +1 -1
- package/commands/task.js +13 -2
- package/commands/unknowns.js +5 -0
- package/commands/verify.js +12 -4
- package/commands/visualize.js +20 -3
- package/commands/workflow.js +23 -7
- package/lib/codex-flight.js +28 -5
- package/lib/dispatch-scout.js +31 -22
- package/lib/engine-registry.js +1482 -13
- package/lib/feedback-triage.js +2 -0
- package/lib/fleet.js +111 -12
- package/lib/host.js +336 -0
- package/lib/improve-vitals-html.js +3 -2
- package/lib/known-commands.js +1 -1
- package/lib/lesson-contradiction.js +2 -2
- package/lib/map-refs.js +226 -0
- package/lib/member-engine.js +253 -0
- package/lib/mission-room.js +4 -4
- package/lib/noninteractive.js +15 -4
- package/lib/policy-lessons.js +1 -1
- package/lib/receipt-block.js +137 -28
- package/lib/roster-markdown.js +206 -0
- package/lib/roster-models.js +179 -0
- package/lib/runner-command.js +95 -15
- package/lib/scorecard.js +4 -4
- package/lib/self-drive.js +9 -1
- package/lib/sleep-sync.js +11 -0
- package/lib/state-detection.js +28 -9
- package/lib/task-db.js +3 -2
- package/lib/todo-fallback.js +1 -1
- package/lib/wish-audit.js +10 -6
- package/lib/wish-delegate.js +29 -5
- package/mcp/atris-mcp/index.mjs +77 -24
- package/package.json +2 -5
- package/scripts/det/det.js +2 -2
- package/scripts/det/pr-description.js +2 -2
- package/scripts/det/test.js +2 -2
- package/templates/members/host/MEMBER.md +23 -0
- package/templates/members/host/MISSION.md +11 -0
- package/templates/members/host/SOUL.md +7 -0
- package/templates/members/host/context/why.md +3 -0
- package/templates/members/host/goals.json +5 -0
- package/templates/members/host/goals.md +3 -0
- package/templates/members/host/skills/host/SKILL.md +13 -0
- package/utils/api.js +1 -1
- package/utils/auth.js +17 -7
- package/utils/backend-root.js +31 -0
- package/utils/config.js +5 -4
- package/utils/owner-identity.js +61 -0
- package/atris/policies/LESSONS.md +0 -13
- package/atris/skills/autopilot/atris-autopilot.md +0 -71
package/scripts/det/det.js
CHANGED
|
@@ -84,7 +84,7 @@ function catalogText() {
|
|
|
84
84
|
);
|
|
85
85
|
const gitRows = GIT_SCRIPTS.map((g) => ` ${g.name.padEnd(15)} ${g.usage}\n ${g.ask}`);
|
|
86
86
|
return (
|
|
87
|
-
'deterministic task scripts
|
|
87
|
+
'deterministic task scripts: run node det.js <script> <mode> < input\n\n' +
|
|
88
88
|
rows.join('\n\n') +
|
|
89
89
|
'\n\ngit-facing (read the repo, run the script directly; not via det.js):\n\n' +
|
|
90
90
|
gitRows.join('\n\n') +
|
|
@@ -121,7 +121,7 @@ async function main() {
|
|
|
121
121
|
}
|
|
122
122
|
const git = GIT_SCRIPTS.find((g) => g.name === script);
|
|
123
123
|
if (git) {
|
|
124
|
-
process.stdout.write(`${git.name} reads the repo, not stdin
|
|
124
|
+
process.stdout.write(`${git.name} reads the repo, not stdin; run it directly:\n ${git.usage}\n`);
|
|
125
125
|
return;
|
|
126
126
|
}
|
|
127
127
|
const entry = CATALOG[script];
|
|
@@ -78,7 +78,7 @@ function areaBullets(files) {
|
|
|
78
78
|
if (counts.A) parts.push(`${counts.A} added`);
|
|
79
79
|
if (counts.M) parts.push(`${counts.M} changed`);
|
|
80
80
|
if (counts.D) parts.push(`${counts.D} removed`);
|
|
81
|
-
bullets.push(`- **${area}
|
|
81
|
+
bullets.push(`- **${area}**: ${parts.join(', ')} (+${added}/-${deleted})`);
|
|
82
82
|
}
|
|
83
83
|
return bullets;
|
|
84
84
|
}
|
|
@@ -108,7 +108,7 @@ function build(input) {
|
|
|
108
108
|
const commits = (input && input.commits) || [];
|
|
109
109
|
const files = (input && input.files) || [];
|
|
110
110
|
if (!commits.length && !files.length) {
|
|
111
|
-
return { error: 'no commits or files vs base
|
|
111
|
+
return { error: 'no commits or files vs base: is the branch ahead of it?' };
|
|
112
112
|
}
|
|
113
113
|
const totals = files.reduce(
|
|
114
114
|
(a, f) => ({ added: a.added + (f.added || 0), deleted: a.deleted + (f.deleted || 0) }),
|
package/scripts/det/test.js
CHANGED
|
@@ -211,7 +211,7 @@ check(
|
|
|
211
211
|
{ path: 'scripts/det/b.js', status: 'M', added: 2, deleted: 1 },
|
|
212
212
|
{ path: 'test/x.test.js', status: 'A', added: 5, deleted: 0 },
|
|
213
213
|
]),
|
|
214
|
-
['- **scripts
|
|
214
|
+
['- **scripts**: 1 added, 1 changed (+12/-1)', '- **test**: 1 added (+5/-0)']
|
|
215
215
|
);
|
|
216
216
|
// test plan lists touched test files, then a check per non-test area
|
|
217
217
|
check(
|
|
@@ -267,7 +267,7 @@ check('det.git.json', JSON.parse(catalogJson()).git['commit-msg'].usage.includes
|
|
|
267
267
|
// stdin catalog stays separate from the git list (routing must not mix them)
|
|
268
268
|
check('det.git.notRoutable', CATALOG['commit-msg'], undefined);
|
|
269
269
|
|
|
270
|
-
console.log(`ok
|
|
270
|
+
console.log(`ok: ${passed} checks passed`);
|
|
271
271
|
|
|
272
272
|
// hunk-filter: keeps only matching hunks, drops non-matching files entirely
|
|
273
273
|
{
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: host
|
|
3
|
+
role: The Host
|
|
4
|
+
description: Gets to know people through fun questions and makes welcome, useful introductions with two private yeses.
|
|
5
|
+
version: 1.0.0
|
|
6
|
+
skills:
|
|
7
|
+
- host
|
|
8
|
+
permissions:
|
|
9
|
+
can-read: true
|
|
10
|
+
can-plan: true
|
|
11
|
+
can-execute: true
|
|
12
|
+
can-approve: false
|
|
13
|
+
approval-required:
|
|
14
|
+
- deliver-message
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
# The Host
|
|
18
|
+
|
|
19
|
+
A warm, discreet companion for a company, club, or personal network. Notice what each person is into and what might help them now. Make a small, concrete invitation when two people could each benefit.
|
|
20
|
+
|
|
21
|
+
Ask people directly. Never read their messages or infer private facts from a quiet week. The human host can see answers, and each person is told this when they join. Published cards contain only the five friendly card sections. Never rank, score, evaluate, or hold people accountable.
|
|
22
|
+
|
|
23
|
+
Read `skills/host/SKILL.md` for the operating loop. The door adapter delivers queued messages. The Host only drafts them.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Mission
|
|
2
|
+
|
|
3
|
+
Help people find conversations they would be glad to have and connections they might otherwise miss.
|
|
4
|
+
|
|
5
|
+
## North Star
|
|
6
|
+
|
|
7
|
+
Useful conversations that both people freely chose.
|
|
8
|
+
|
|
9
|
+
## Boundaries
|
|
10
|
+
|
|
11
|
+
Ask one fun question every few days. Keep a private memory and a small published card per person. Only introduce two people after two private yeses. Never reveal a no, read private messages, score people, or use a manager relationship as an introduction suggestion.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# The Host's soul
|
|
2
|
+
|
|
3
|
+
Be on each person's side. Noticing a small win or a timely need is the start of a good relationship.
|
|
4
|
+
|
|
5
|
+
Trust comes first. A thin signal is a reason to ask, not a reason to assume. One thoughtful introduction is better than ten plausible ones. A private no stays private.
|
|
6
|
+
|
|
7
|
+
Sound like a thoughtful friend: curious, specific, and easy to decline.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Host operating loop
|
|
2
|
+
|
|
3
|
+
Run in a workspace with `atris/`. Use `atris host <subcommand> --json` to read machine output. Treat all private paths as host-only. A door adapter alone delivers queued messages, then calls `atris host sent <message-id>`.
|
|
4
|
+
|
|
5
|
+
1. Run `atris host due`. For each person, read their private record and published card. Pick one playful question that fills a real gap in the card. Ask with `atris host ask <id> --question "..."`. Do not repeat a question or pressure someone who goes quiet.
|
|
6
|
+
2. Let the door adapter pass replies to `atris host receive --event-id <door-event-id> --from <door-or-id> --text "..."`. Drain them before deciding what to do next. Update a published card with `atris host card <id> --patch <file.json> --expected-revision <revision>`. Keep answers and operational fields out of the card.
|
|
7
|
+
3. Record a known connection with `atris host link <a> <b> --source channel|answer|card --evidence "..."`. Use `card` only for a tentative clue. The code blocks introductions when another source confirms a link.
|
|
8
|
+
Record a link only when two people already know each other. "Wants to meet" belongs on the card, not in links.
|
|
9
|
+
4. Propose at most one introduction per person in 30 days. Name a current, specific benefit for each person and one small activity they could do together. Shared interests alone are not enough. Check existing links and exclude manager and report pairs. Draft the exact text, then call `atris host propose <a> <b> --reason "..." --activity "..." --text "..."`. Two private yeses are required. A no is never disclosed.
|
|
10
|
+
An introduction reason may use only what is already on both published cards, never private answers.
|
|
11
|
+
5. Once a week run `atris host room`. Notice people with no connections recorded, celebrations, introductions in flight, and people to welcome. Use this as a gentle prompt, never a ranking or performance report.
|
|
12
|
+
|
|
13
|
+
On `leave`, `pause`, or `forget`, respect the person's choice. Never read anyone's messages outside the answers explicitly handed to the Host. Never send directly from this skill.
|
package/utils/api.js
CHANGED
|
@@ -97,7 +97,7 @@ function httpRequest(urlString, options) {
|
|
|
97
97
|
// Socket idle timeout (fires if no data received for this duration)
|
|
98
98
|
if (timeoutMs > 0) {
|
|
99
99
|
req.setTimeout(timeoutMs, () => {
|
|
100
|
-
req.destroy(new Error(`
|
|
100
|
+
req.destroy(new Error(`request timeout after ${Math.round(timeoutMs / 1000)}s, try --timeout=300`));
|
|
101
101
|
});
|
|
102
102
|
}
|
|
103
103
|
// Hard deadline — kill request after 2x the timeout regardless of activity
|
package/utils/auth.js
CHANGED
|
@@ -156,6 +156,20 @@ function mkPrivateDir(dir) {
|
|
|
156
156
|
return dir;
|
|
157
157
|
}
|
|
158
158
|
|
|
159
|
+
// Credential files hold login tokens. If they cannot be limited to the owner,
|
|
160
|
+
// say so once per file instead of leaving them readable in silence.
|
|
161
|
+
const permissionWarned = new Set();
|
|
162
|
+
function restrictToOwner(filePath) {
|
|
163
|
+
try {
|
|
164
|
+
fs.chmodSync(filePath, 0o600);
|
|
165
|
+
} catch (err) {
|
|
166
|
+
if (permissionWarned.has(filePath)) return;
|
|
167
|
+
permissionWarned.add(filePath);
|
|
168
|
+
const reason = err && err.code ? ` (${err.code})` : '';
|
|
169
|
+
console.error(`atris: could not limit ${filePath} to your user${reason}. other users on this machine may be able to read it.`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
159
173
|
function getAtrisDir() {
|
|
160
174
|
const homeDir = os.homedir();
|
|
161
175
|
return mkPrivateDir(path.join(homeDir, '.atris'));
|
|
@@ -349,7 +363,7 @@ function getProfilesDir() {
|
|
|
349
363
|
|
|
350
364
|
function profileNameFromEmail(email) {
|
|
351
365
|
if (!email) return null;
|
|
352
|
-
// "
|
|
366
|
+
// "alex@example.com" becomes "alex".
|
|
353
367
|
const name = email.split('@')[0].toLowerCase().replace(/[^a-z0-9_-]/g, '-');
|
|
354
368
|
return name || null; // Guard against emails like "@domain.com"
|
|
355
369
|
}
|
|
@@ -357,7 +371,7 @@ function profileNameFromEmail(email) {
|
|
|
357
371
|
function saveProfile(name, credentials) {
|
|
358
372
|
const profilePath = path.join(getProfilesDir(), `${name}.json`);
|
|
359
373
|
fs.writeFileSync(profilePath, JSON.stringify(credentials, null, 2));
|
|
360
|
-
|
|
374
|
+
restrictToOwner(profilePath);
|
|
361
375
|
}
|
|
362
376
|
|
|
363
377
|
function loadProfile(name) {
|
|
@@ -413,11 +427,7 @@ function saveCredentials(token, refreshToken, email, userId, provider, extras =
|
|
|
413
427
|
};
|
|
414
428
|
|
|
415
429
|
fs.writeFileSync(credentialsPath, JSON.stringify(credentials, null, 2));
|
|
416
|
-
|
|
417
|
-
fs.chmodSync(credentialsPath, 0o600);
|
|
418
|
-
} catch {
|
|
419
|
-
// Best effort: permissions may be unsupported on this platform.
|
|
420
|
-
}
|
|
430
|
+
restrictToOwner(credentialsPath);
|
|
421
431
|
|
|
422
432
|
// Auto-save as named profile
|
|
423
433
|
autoSaveProfile(credentials);
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { resolveWorkspaceRoot } = require('../lib/mission-root');
|
|
6
|
+
const { loadConfig } = require('./config');
|
|
7
|
+
|
|
8
|
+
const BACKEND_ROOT_HINT = 'set ATRIS_BACKEND_ROOT to the backend workspace.';
|
|
9
|
+
|
|
10
|
+
function resolveBackendRoot(cwd = process.cwd()) {
|
|
11
|
+
const workspace = resolveWorkspaceRoot(cwd);
|
|
12
|
+
// ATRIS_BACKEND_DIR is the former spelling, accepted only here.
|
|
13
|
+
const environment = process.env.ATRIS_BACKEND_ROOT || process.env.ATRIS_BACKEND_DIR;
|
|
14
|
+
if (environment) {
|
|
15
|
+
const candidate = path.resolve(environment);
|
|
16
|
+
return fs.existsSync(candidate) && fs.statSync(candidate).isDirectory() ? candidate : null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const config = loadConfig(workspace);
|
|
20
|
+
if (typeof config?.backend_root === 'string' && config.backend_root.trim()) {
|
|
21
|
+
const candidate = path.resolve(workspace, config.backend_root);
|
|
22
|
+
return fs.existsSync(candidate) && fs.statSync(candidate).isDirectory() ? candidate : null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const sibling = path.resolve(workspace, '..', 'atrisos-backend');
|
|
26
|
+
if (fs.existsSync(sibling) && fs.statSync(sibling).isDirectory()) return sibling;
|
|
27
|
+
const installedSibling = path.resolve(__dirname, '..', '..', 'atrisos-backend');
|
|
28
|
+
return fs.existsSync(installedSibling) && fs.statSync(installedSibling).isDirectory() ? installedSibling : null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
module.exports = { BACKEND_ROOT_HINT, resolveBackendRoot };
|
package/utils/config.js
CHANGED
|
@@ -5,17 +5,18 @@ const path = require('path');
|
|
|
5
5
|
* Get the path to atris/.config in the current project.
|
|
6
6
|
* @returns {string} Config file path
|
|
7
7
|
*/
|
|
8
|
-
function getConfigPath() {
|
|
9
|
-
const targetDir = path.join(
|
|
8
|
+
function getConfigPath(root = process.cwd()) {
|
|
9
|
+
const targetDir = path.join(root, 'atris');
|
|
10
10
|
return path.join(targetDir, '.config');
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* Load config from atris/.config, returning empty object if missing/invalid.
|
|
15
|
+
* backend_root may name a backend folder relative to the workspace root.
|
|
15
16
|
* @returns {Object} Config object
|
|
16
17
|
*/
|
|
17
|
-
function loadConfig() {
|
|
18
|
-
const configPath = getConfigPath();
|
|
18
|
+
function loadConfig(root = process.cwd()) {
|
|
19
|
+
const configPath = getConfigPath(root);
|
|
19
20
|
|
|
20
21
|
if (!fs.existsSync(configPath)) {
|
|
21
22
|
return {};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const os = require('os');
|
|
4
|
+
const { spawnSync } = require('child_process');
|
|
5
|
+
const { loadCredentials, profileNameFromEmail } = require('./auth');
|
|
6
|
+
|
|
7
|
+
let cachedIdentity = null;
|
|
8
|
+
|
|
9
|
+
function localUsername() {
|
|
10
|
+
try {
|
|
11
|
+
return os.userInfo().username;
|
|
12
|
+
} catch {
|
|
13
|
+
return process.env.USER || process.env.LOGNAME || null;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function gitUserName() {
|
|
18
|
+
const result = spawnSync('git', ['config', 'user.name'], { encoding: 'utf8' });
|
|
19
|
+
return result.status === 0 ? String(result.stdout || '').trim() : null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function buildOwnerIdentity(credentials, username) {
|
|
23
|
+
const inheritedNames = String(process.env.ATRIS_OWNER_NAMES || '').split(',').map((name) => name.trim()).filter(Boolean);
|
|
24
|
+
const emailName = profileNameFromEmail(credentials?.email);
|
|
25
|
+
const configured = process.env.ATRIS_OPERATOR;
|
|
26
|
+
const fullName = credentials?.name || credentials?.full_name || credentials?.user_metadata?.full_name;
|
|
27
|
+
const loggedIn = Boolean(emailName || credentials?.username || credentials?.user_id || fullName);
|
|
28
|
+
const gitName = loggedIn ? null : gitUserName();
|
|
29
|
+
const gitFirstName = gitName ? gitName.split(/\s+/)[0] : null;
|
|
30
|
+
// Keep an existing local claim alias when it begins with the signed-in account name.
|
|
31
|
+
const localAlias = username && emailName?.length >= 4 && String(username).toLowerCase().startsWith(emailName)
|
|
32
|
+
? username : null;
|
|
33
|
+
const values = [
|
|
34
|
+
...inheritedNames, emailName, configured, credentials?.username, credentials?.user_id, fullName,
|
|
35
|
+
fullName?.replace(/\s+/g, ''), localAlias, gitName, gitName?.replace(/\s+/g, ''),
|
|
36
|
+
gitFirstName, loggedIn ? null : username,
|
|
37
|
+
]
|
|
38
|
+
.filter(Boolean)
|
|
39
|
+
.map((value) => String(value).toLowerCase());
|
|
40
|
+
const slug = inheritedNames[0] || emailName || configured || gitFirstName || (loggedIn ? null : username);
|
|
41
|
+
return { slug: slug ? String(slug).toLowerCase() : null, names: values };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function ownerIdentity(credentials, username) {
|
|
45
|
+
if (arguments.length > 0) return buildOwnerIdentity(credentials, username === undefined ? localUsername() : username);
|
|
46
|
+
if (!cachedIdentity) cachedIdentity = buildOwnerIdentity(loadCredentials(), localUsername());
|
|
47
|
+
return cachedIdentity;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function resetOwnerIdentityCache() {
|
|
51
|
+
cachedIdentity = null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function isOwner(value) {
|
|
55
|
+
const candidate = String(value || '').trim().toLowerCase();
|
|
56
|
+
if (['you', 'me', 'operator', 'human', 'owner'].includes(candidate)) return true;
|
|
57
|
+
const identity = ownerIdentity();
|
|
58
|
+
return identity.names.includes(candidate);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
module.exports = { ownerIdentity, isOwner, resetOwnerIdentityCache };
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
# LESSONS
|
|
2
|
-
|
|
3
|
-
Purpose: Capture short, actionable lessons after REVIEW misses.
|
|
4
|
-
|
|
5
|
-
## Rules
|
|
6
|
-
- Add only after REVIEW when there was a miss, mismatch, or new constraint.
|
|
7
|
-
- One line per lesson.
|
|
8
|
-
- Format: YYYY-MM-DD | area | issue -> fix
|
|
9
|
-
- Promote repeated lessons (2-3 times) into the relevant policy, then delete.
|
|
10
|
-
|
|
11
|
-
## Entries
|
|
12
|
-
- 2026-01-04 | meta | JSON edits break easily on quote boundaries → use Read tool to verify after Edit on .json files
|
|
13
|
-
- 2026-01-28 | init | Meta-frameworks must be detected before base frameworks → Next.js check before React check (tests caught this)
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Start autonomous loop - plan/do/review until done
|
|
3
|
-
arguments:
|
|
4
|
-
- name: task
|
|
5
|
-
description: What to build (e.g., "Add dark mode toggle")
|
|
6
|
-
required: true
|
|
7
|
-
- name: max-iterations
|
|
8
|
-
description: Max loops before stopping (default 10)
|
|
9
|
-
required: false
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
# Atris Autopilot
|
|
13
|
-
|
|
14
|
-
You are entering **autonomous mode**. You will loop until the task is complete or max iterations reached.
|
|
15
|
-
|
|
16
|
-
## Setup
|
|
17
|
-
|
|
18
|
-
First, create the state file:
|
|
19
|
-
|
|
20
|
-
```bash
|
|
21
|
-
mkdir -p .claude
|
|
22
|
-
cat > .claude/atris-autopilot.state.md << 'EOF'
|
|
23
|
-
---
|
|
24
|
-
iteration: 1
|
|
25
|
-
max_iterations: $ARGUMENTS.max-iterations|default:10
|
|
26
|
-
completion_promise: <promise>COMPLETE</promise>
|
|
27
|
-
---
|
|
28
|
-
|
|
29
|
-
$ARGUMENTS.task
|
|
30
|
-
EOF
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
## Your Task
|
|
34
|
-
|
|
35
|
-
**$ARGUMENTS.task**
|
|
36
|
-
|
|
37
|
-
## Process
|
|
38
|
-
|
|
39
|
-
Each iteration:
|
|
40
|
-
1. **PLAN** — Read MAP.md, identify files, create approach
|
|
41
|
-
2. **DO** — Implement ONE thing, commit changes
|
|
42
|
-
3. **REVIEW** — Check acceptance criteria
|
|
43
|
-
|
|
44
|
-
## Acceptance Criteria
|
|
45
|
-
|
|
46
|
-
- Task implemented and working
|
|
47
|
-
- Tests pass (if they exist)
|
|
48
|
-
- Build passes
|
|
49
|
-
- Code follows patterns in MAP.md
|
|
50
|
-
|
|
51
|
-
## Rules
|
|
52
|
-
|
|
53
|
-
- ONE thing per iteration (trust the loop)
|
|
54
|
-
- Search MAP.md before grepping
|
|
55
|
-
- Search codebase before assuming not implemented
|
|
56
|
-
- Update TODO.md with progress
|
|
57
|
-
- Log learnings to atris/logs/
|
|
58
|
-
|
|
59
|
-
## Completion
|
|
60
|
-
|
|
61
|
-
When ALL acceptance criteria pass, output exactly:
|
|
62
|
-
|
|
63
|
-
```
|
|
64
|
-
<promise>COMPLETE</promise>
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
This signals the stop hook to end the loop.
|
|
68
|
-
|
|
69
|
-
## Start
|
|
70
|
-
|
|
71
|
-
Read atris/MAP.md now. Then begin iteration 1.
|