atris 3.45.1 → 3.46.1
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 +19 -3
- package/FOR_AGENTS.md +5 -0
- package/README.md +2 -2
- package/atris/AGENTS.md +4 -3
- package/atris/CLAUDE.md +1 -1
- package/atris/atris.md +21 -1
- package/atris/skills/atris/SKILL.md +7 -3
- package/atris/skills/loop/SKILL.md +6 -3
- package/atris.md +18 -1
- package/bin/atris.js +5 -0
- package/commands/autoland.js +25 -3
- package/commands/brain.js +14 -3
- package/commands/ci.js +44 -0
- package/commands/codex-goal.js +21 -119
- package/commands/init.js +33 -10
- package/commands/mission.js +116 -53
- package/commands/pack.js +90 -25
- package/commands/sync.js +34 -6
- package/commands/task.js +239 -31
- package/commands/voice.js +12 -2
- package/lib/ci-runner.js +396 -0
- package/lib/engine-validate.js +141 -1
- package/lib/known-commands.js +1 -1
- package/lib/task-db.js +22 -3
- package/lib/task-explanation.js +229 -0
- package/lib/todo-fallback.js +6 -0
- package/lib/voice-card.js +258 -0
- package/package.json +1 -1
- package/templates/research-canonical/atris.md +6 -0
package/AGENTS.md
CHANGED
|
@@ -86,7 +86,8 @@ Human accept -> task Done + AgentXP awarded
|
|
|
86
86
|
```
|
|
87
87
|
|
|
88
88
|
Always-on agents should move proof-backed work to Review, complete their native
|
|
89
|
-
goal, then
|
|
89
|
+
goal, then stop that task. The next goal or recurring monitor starts in a new
|
|
90
|
+
dedicated task. They must not run
|
|
90
91
|
`atris task accept` or claim AgentXP themselves; acceptance comes from a human
|
|
91
92
|
or from the owner's standing `atris autoland` policy, never from the agent.
|
|
92
93
|
|
|
@@ -100,8 +101,8 @@ falling back to manual task/worktree flow.
|
|
|
100
101
|
|
|
101
102
|
Codex agents with native goal tools should run `atris mission goal --json`
|
|
102
103
|
before choosing work. If the payload includes `goal.visible_goal`, mirror
|
|
103
|
-
`goal.objective`
|
|
104
|
-
|
|
104
|
+
`goal.objective` when this active task has no goal yet or its goal already
|
|
105
|
+
matches; never reuse a completed task or complete unrelated active goals just to
|
|
105
106
|
make room.
|
|
106
107
|
|
|
107
108
|
## Workflow
|
|
@@ -230,6 +231,21 @@ Purpose: optimize for decision-speed; lead with the move, then use descriptions
|
|
|
230
231
|
Shape: `<operator>, today is about <move>` -> `I picked this because <why now>` -> `Ready: <draft/proof/context>` -> `Go deeper: <paths>`.
|
|
231
232
|
Definitions: operator = current person or agent; move = one concrete high-leverage workflow; why now = business reason; ready = prepared action or proof; paths = 2-4 optional deeper views.
|
|
232
233
|
|
|
234
|
+
Keep this voice beside every reply:
|
|
235
|
+
<!-- ATRIS_VOICE_CARD:START -->
|
|
236
|
+
## Voice card
|
|
237
|
+
|
|
238
|
+
Start with the answer, then give the reader only what helps them act. Name the exact thing in plain words, like you are talking to a person.
|
|
239
|
+
|
|
240
|
+
Keep each paragraph to one or two sentences and leave a blank line between thoughts. Use a comma or period instead of an em dash.
|
|
241
|
+
|
|
242
|
+
Status example:
|
|
243
|
+
The reply check is built. I am running the final checks now, so the result is not ready yet.
|
|
244
|
+
|
|
245
|
+
Landing example:
|
|
246
|
+
Replies now get a plain-language check before they reach you. The checks passed, and the change is ready.
|
|
247
|
+
<!-- ATRIS_VOICE_CARD:END -->
|
|
248
|
+
|
|
233
249
|
Re-run after meaningful work:
|
|
234
250
|
`atris brain compile --root .`
|
|
235
251
|
<!-- ATRIS_BRAIN_COMPILE:END -->
|
package/FOR_AGENTS.md
CHANGED
|
@@ -50,6 +50,11 @@ atris task ready <id> --proof "command that passed"
|
|
|
50
50
|
|
|
51
51
|
**Never** `atris task accept` unless a human approved. That's their gate, not yours.
|
|
52
52
|
|
|
53
|
+
Every task starts with three plain sentences: what changes, why it matters, and
|
|
54
|
+
what done looks like. Keep the exact title, files, commands, requirements,
|
|
55
|
+
events, proof, and approval rules available underneath. Offer the existing
|
|
56
|
+
approve-or-change actions without weakening any proof or human approval gate.
|
|
57
|
+
|
|
53
58
|
---
|
|
54
59
|
|
|
55
60
|
## Rules that make you trustworthy
|
package/README.md
CHANGED
|
@@ -217,7 +217,7 @@ atris business record atris/reports/2026-04-12-operator-recap.md --outcome mixed
|
|
|
217
217
|
| `atris play` | Enter the AgentXP player loop for one proof-backed mission |
|
|
218
218
|
| `atris gm` | Enter AgentXP General Manager mode for player missions and review queues |
|
|
219
219
|
| `atris xp` | Show the local AgentXP card and sync eligible proof to the hosted leaderboard |
|
|
220
|
-
| `atris codex-goal` | Inspect
|
|
220
|
+
| `atris codex-goal` | Inspect native Codex task goals and keep completed tasks closed |
|
|
221
221
|
| `atris learn` | Manage structured learnings |
|
|
222
222
|
| `atris ingest` | Stage raw evidence into `atris/context/` and compile into `atris/wiki/` |
|
|
223
223
|
| `atris loop` | Refresh wiki health, stale/orphan signals, and next ingest candidates |
|
|
@@ -238,7 +238,7 @@ atris business record atris/reports/2026-04-12-operator-recap.md --outcome mixed
|
|
|
238
238
|
- `atris loop` refreshes `atris/wiki/STATUS.md` and `atris/wiki/log.md`, flags stale/orphan pages, and suggests the next ingest
|
|
239
239
|
- `atris activate` loads the current wiki status so the next session starts with project memory, not just tasks
|
|
240
240
|
- `atris member` keeps team-member identity and learning local-first: `MEMBER.md` is the role contract, `goals.json` is the machine-readable goal/experiment state, `goals.md` is the human readout, and `logs/YYYY-MM-DD.md` records what happened. Use `atris member goal`, `tick`, `status`, `block`, and `review --value 1..5` to test whether a member is making useful progress or needs the operator/orchestrator.
|
|
241
|
-
- `atris codex-goal` is the
|
|
241
|
+
- `atris codex-goal` is the read-only bridge for native Codex `/goal`: `status` inspects the live goal database, while the legacy `reset` command now refuses every mutation. Active tasks continue in place; completed tasks retain their final goal, and new work or recurring monitors use a new dedicated Codex task.
|
|
242
242
|
- `atris task` keeps durable local task state and append-only events for agents; `atris/TODO.md` is just a regenerated readable board. Run the loop with `atris task new`, `delegate "..." --to <owner>`, `next`, `say`, and `ready <id> --proof "..."`; human approval is `atris task accept <id>` (moves to Done, awards Career XP) or `revise <id> --note "..."`. Final task transitions also append the general daily log and, when a real `atris/team/<member>/MEMBER.md` matches the task owner, that member's daily log. Add `--json` for headless agents, `atris task serve` for the local board, and `atris task show <ref>` / `events --all` for the full ledger. Commands accept semantic refs (`OBL-18`), full IDs, or any unique prefix. In cloud business workspaces, Supabase `tasks` is the source of truth and Swarlo the live claim layer.
|
|
243
243
|
- `atris mission` is the durable autonomy layer: start with an owner, verifier, runner, and stop condition; record bounded work with `mission tick`; close with `mission complete` only after proof. Runners include `manual`, `claude`, `atris2`, and `codex_goal`.
|
|
244
244
|
- `atris pulse` is the OS-cron heartbeat for overnight self-improvement. Use `atris pulse status`, `tick`, `run`, `install --cadence "<cron>" --days 7 --verify "npm test" --model claude-opus-4-8`, and `uninstall`.
|
package/atris/AGENTS.md
CHANGED
|
@@ -56,13 +56,14 @@ Human accept -> task Done + Career XP awarded
|
|
|
56
56
|
```
|
|
57
57
|
|
|
58
58
|
Always-on agents should move proof-backed work to Review, complete their native
|
|
59
|
-
goal, then
|
|
59
|
+
goal, then stop that task. The next goal or recurring monitor starts in a new
|
|
60
|
+
dedicated task. They must not run
|
|
60
61
|
`atris task accept` or claim Career XP unless a human approved the proof.
|
|
61
62
|
|
|
62
63
|
Codex agents with native goal tools should run `atris mission goal --json`
|
|
63
64
|
before choosing work. If the payload includes `goal.visible_goal`, mirror
|
|
64
|
-
`goal.objective`
|
|
65
|
-
|
|
65
|
+
`goal.objective` when this active task has no goal yet or its goal already
|
|
66
|
+
matches; never reuse a completed task or complete unrelated active goals just to
|
|
66
67
|
make room.
|
|
67
68
|
|
|
68
69
|
Default to the current checkout for small, clean, single-agent fixes. Use
|
package/atris/CLAUDE.md
CHANGED
|
@@ -48,7 +48,7 @@ Agent proof ready -> native goal can complete
|
|
|
48
48
|
Human accept -> task Done + AgentXP awarded
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
-
Always-on agents should complete their native goal after proof is in Review, then
|
|
51
|
+
Always-on agents should complete their native goal after proof is in Review, then stop that task. The next goal or recurring monitor starts in a new dedicated task. They must not run `atris task accept` or claim AgentXP unless a human approved the proof.
|
|
52
52
|
|
|
53
53
|
Do not write new operating doctrine here first. Add it to Atris policy, skills, wiki, or `atris/atris.md`, then regenerate this adapter if needed.
|
|
54
54
|
|
package/atris/atris.md
CHANGED
|
@@ -96,7 +96,10 @@ Core loop:
|
|
|
96
96
|
|
|
97
97
|
```bash
|
|
98
98
|
atris task list
|
|
99
|
-
atris task delegate "<title>" --to <functional-member> --tag <tag>
|
|
99
|
+
atris task delegate "<title>" --to <functional-member> --tag <tag> \
|
|
100
|
+
--what-changes "<plain change>" \
|
|
101
|
+
--why-it-matters "<plain reason>" \
|
|
102
|
+
--done-looks-like "<observable finish>"
|
|
100
103
|
atris task delegate "<title>" --to <functional-member> --executed-by <engine> --via swarlo --tag <tag>
|
|
101
104
|
atris task day
|
|
102
105
|
atris task next
|
|
@@ -108,6 +111,9 @@ atris task review <id> --lesson "<what improved>" --next "<next task>"
|
|
|
108
111
|
|
|
109
112
|
`atris task ready` carries `--result`, the day-one PM sentence of what the human gained; the CLI refuses agent-speak.
|
|
110
113
|
|
|
114
|
+
One purpose lives in one task. Once a native Codex task is complete, keep its
|
|
115
|
+
final state intact; new work and recurring monitors start in a dedicated task.
|
|
116
|
+
|
|
111
117
|
Headless agents should add `--json` where available and read
|
|
112
118
|
`.atris/state/tasks.projection.json` for a compact board view.
|
|
113
119
|
|
|
@@ -122,6 +128,9 @@ task row/event stream remains the durable source of truth.
|
|
|
122
128
|
Every task record should carry:
|
|
123
129
|
|
|
124
130
|
```
|
|
131
|
+
What changes: <plain sentence a new teammate understands>
|
|
132
|
+
Why it matters: <plain human or business reason>
|
|
133
|
+
Done looks like: <observable finish, without command syntax>
|
|
125
134
|
Title: <small work packet>
|
|
126
135
|
Owner: <functional or feature member, not an engine>
|
|
127
136
|
Objective: <why this matters>
|
|
@@ -131,6 +140,17 @@ Verify: <shell command or concrete proof>
|
|
|
131
140
|
Next: <suggested follow-up task>
|
|
132
141
|
```
|
|
133
142
|
|
|
143
|
+
The three plain fields are the default face on every task view. The exact
|
|
144
|
+
title, context, requirements, files, events, proof, and verifier stay beneath
|
|
145
|
+
them unchanged and inspectable. If a creator omits a plain field, the shared
|
|
146
|
+
task model derives an honest fallback from the existing task and says when no
|
|
147
|
+
reason was recorded; it never invents a benefit.
|
|
148
|
+
|
|
149
|
+
A planned task shows two clear actions: approve the complete plan through the
|
|
150
|
+
existing Plan -> Do gate, or ask for a change. Completed work shows approve
|
|
151
|
+
only when the existing proof and human-accept gates allow it, plus revise for
|
|
152
|
+
requested changes. The plain layer never bypasses a verifier or approval rule.
|
|
153
|
+
|
|
134
154
|
Task planning preview and landing:
|
|
135
155
|
|
|
136
156
|
```
|
|
@@ -32,6 +32,9 @@ Key behaviors:
|
|
|
32
32
|
- Read PERSONA.md (3-4 sentences, ASCII visuals)
|
|
33
33
|
- Check MAP.md for file:line refs
|
|
34
34
|
- Use `atris task` for claims, proof, ready, and accept
|
|
35
|
+
- Give every task a plain first layer: what changes, why it matters, and what
|
|
36
|
+
done looks like. Keep the exact task record beneath it and use the existing
|
|
37
|
+
approve/change gates without weakening proof or human acceptance.
|
|
35
38
|
- Use functional/feature members as task owners; record engines only as `executed_by`
|
|
36
39
|
- Treat TODO.md as a rendered view; regenerate it instead of hand-editing tasks
|
|
37
40
|
- In Codex runtimes with native goal tools, mirror `atris mission goal --json` into the visible chat goal via `goal.visible_goal`
|
|
@@ -67,9 +70,10 @@ If it returns `action: codex_goal_candidate` or `codex_goal_heartbeat` with
|
|
|
67
70
|
|
|
68
71
|
1. Call `get_goal` when the runtime exposes it.
|
|
69
72
|
2. If the active goal already equals `goal.objective`, keep working.
|
|
70
|
-
3. If
|
|
71
|
-
4. If
|
|
72
|
-
5.
|
|
73
|
+
3. If this active task has no goal yet, call `create_goal` with `goal.objective`.
|
|
74
|
+
4. If this task's prior goal is complete, stop. Create a new dedicated Codex task for the next objective or recurring monitor; never reset or reuse the completed task.
|
|
75
|
+
5. If a different active goal is still in progress, do not complete it just to make room; report that `goal.visible_goal.status` is waiting for the visible goal slot.
|
|
76
|
+
6. After proof is ready, call `update_goal({ status: "complete" })` and stop this task. Read the next candidate only from its own new Codex task.
|
|
73
77
|
|
|
74
78
|
Native goal completion is not task acceptance. Agents may complete their native
|
|
75
79
|
goal after proof is ready; only a human should run `atris task accept`.
|
|
@@ -19,6 +19,7 @@ Schedules the recurring autopilot heartbeat. One tick fires roughly every 13–1
|
|
|
19
19
|
2. The cron prompt first invokes `atris mission run --due --max-ticks 1 --complete-on-pass`; if no mission is due, it invokes `/autopilot`
|
|
20
20
|
3. Returns the cron job id so the user can stop it later with `CronDelete`
|
|
21
21
|
4. Lists the active cron jobs via `CronList` so the user can see the heartbeat is alive
|
|
22
|
+
5. Runs from a dedicated active task for this loop; a completed task is never reused as the scheduler host
|
|
22
23
|
|
|
23
24
|
## How to invoke
|
|
24
25
|
|
|
@@ -26,13 +27,14 @@ User says "run /loop", "start the loop", "kick off autonomous mode", or "make au
|
|
|
26
27
|
|
|
27
28
|
The agent then:
|
|
28
29
|
|
|
29
|
-
1.
|
|
30
|
+
1. Checks that the current task is active and dedicated to this loop. If it is complete or belongs to other work, stop and create a new dedicated task before scheduling.
|
|
31
|
+
2. Calls `CronCreate` with these args (use whatever off-clock minute you land on, do not pin to :00 or :30):
|
|
30
32
|
- `cron`: `"*/13 * * * *"` (every 13 min) for tight loops, or `"7 * * * *"` (hourly at :07) for slow loops
|
|
31
33
|
- `prompt`: `"First run: atris mission run --due --max-ticks 1 --complete-on-pass. If it reports no_due_mission, run /autopilot for one tick. One bounded goal only, then stop. Do not start a conversation."`
|
|
32
34
|
- `recurring`: `true`
|
|
33
35
|
- `durable`: `false` (in-memory only, gone when this Claude session ends)
|
|
34
|
-
|
|
35
|
-
|
|
36
|
+
3. After creating, calls `CronList` and shows the user the active cron jobs.
|
|
37
|
+
4. Tells the user: "loop is alive. job id <X>. fires roughly every <N> minutes. say 'stop the loop' to kill it. auto-expires after 7 days."
|
|
36
38
|
|
|
37
39
|
## Stopping the loop
|
|
38
40
|
|
|
@@ -43,6 +45,7 @@ If the user says "kill all loops", call `CronList`, then `CronDelete` for every
|
|
|
43
45
|
## Rules
|
|
44
46
|
|
|
45
47
|
- One tick at a time. Never schedule a cron that fires more than once per 10 min.
|
|
48
|
+
- One recurring monitor per dedicated active task. Never attach a new monitor to a completed task.
|
|
46
49
|
- Always pick an off-clock minute (avoid :00 and :30) to prevent the global fleet from hammering the API at the same instant.
|
|
47
50
|
- Use `durable: false` by default. Only use `durable: true` if the user explicitly says "make this survive restarts" or "persist this".
|
|
48
51
|
- Auto-expires after 7 days. Tell the user.
|
package/atris.md
CHANGED
|
@@ -139,7 +139,10 @@ Core loop:
|
|
|
139
139
|
|
|
140
140
|
```bash
|
|
141
141
|
atris task list
|
|
142
|
-
atris task delegate "<title>" --to <functional-member> --tag <tag>
|
|
142
|
+
atris task delegate "<title>" --to <functional-member> --tag <tag> \
|
|
143
|
+
--what-changes "<plain change>" \
|
|
144
|
+
--why-it-matters "<plain reason>" \
|
|
145
|
+
--done-looks-like "<observable finish>"
|
|
143
146
|
atris task delegate "<title>" --to <functional-member> --executed-by <engine> --via swarlo --tag <tag>
|
|
144
147
|
atris task day
|
|
145
148
|
atris task next
|
|
@@ -163,6 +166,9 @@ task row/event stream remains the durable source of truth.
|
|
|
163
166
|
Every task record should carry:
|
|
164
167
|
|
|
165
168
|
```
|
|
169
|
+
What changes: <plain sentence a new teammate understands>
|
|
170
|
+
Why it matters: <plain human or business reason>
|
|
171
|
+
Done looks like: <observable finish, without command syntax>
|
|
166
172
|
Title: <small work packet>
|
|
167
173
|
Owner: <functional or feature member, not an engine>
|
|
168
174
|
Objective: <why this matters>
|
|
@@ -172,6 +178,17 @@ Verify: <shell command or concrete proof>
|
|
|
172
178
|
Next: <suggested follow-up task>
|
|
173
179
|
```
|
|
174
180
|
|
|
181
|
+
The three plain fields are the default face on every task view. The exact
|
|
182
|
+
title, context, requirements, files, events, proof, and verifier stay beneath
|
|
183
|
+
them unchanged and inspectable. If a creator omits a plain field, the shared
|
|
184
|
+
task model derives an honest fallback from the existing task and says when no
|
|
185
|
+
reason was recorded; it never invents a benefit.
|
|
186
|
+
|
|
187
|
+
A planned task shows two clear actions: approve the complete plan through the
|
|
188
|
+
existing Plan -> Do gate, or ask for a change. Completed work shows approve
|
|
189
|
+
only when the existing proof and human-accept gates allow it, plus revise for
|
|
190
|
+
requested changes. The plain layer never bypasses a verifier or approval rule.
|
|
191
|
+
|
|
175
192
|
Task planning preview and landing:
|
|
176
193
|
|
|
177
194
|
```
|
package/bin/atris.js
CHANGED
|
@@ -565,6 +565,7 @@ function showHelp() {
|
|
|
565
565
|
console.log(' drive - One self-driving tick: mission doctor -> auto-fix -> count disengagements');
|
|
566
566
|
console.log(` autoland - Approve the policy once; ${require('../lib/autoland').certifiedWorkLandsPhrase(process.cwd())}, you keep irreversible calls`);
|
|
567
567
|
console.log(' engine - engine registry, answer validation, dispatch flights, and live progress');
|
|
568
|
+
console.log(' ci - run github actions jobs locally with runs-on: atris');
|
|
568
569
|
console.log(' router - inspect ax lane outcomes and promote gated reflex overrides');
|
|
569
570
|
console.log(' sign - Co-author trailer on every commit in an atris workspace (on/off/status)');
|
|
570
571
|
console.log(' visualize - Generate a Slack/deck-ready visual from a prompt');
|
|
@@ -2619,6 +2620,10 @@ if (command === 'init') {
|
|
|
2619
2620
|
require('../commands/game').gameCommand(process.argv.slice(3))
|
|
2620
2621
|
.then((status) => process.exit(status === 1 ? 1 : 0))
|
|
2621
2622
|
.catch((err) => { console.error(`✗ Error: ${err.message || err}`); process.exit(1); });
|
|
2623
|
+
} else if (command === 'ci') {
|
|
2624
|
+
Promise.resolve(require('../commands/ci').ciCommand(process.argv.slice(3)))
|
|
2625
|
+
.then((status) => process.exit(status || 0))
|
|
2626
|
+
.catch((err) => { console.error(String(err.message || err).replace(/\s+/g, ' ').toLowerCase()); process.exit(1); });
|
|
2622
2627
|
} else if (command === 'github') {
|
|
2623
2628
|
const status = require('../commands/github').githubCommand(process.argv.slice(3));
|
|
2624
2629
|
process.exit(status);
|
package/commands/autoland.js
CHANGED
|
@@ -9,6 +9,7 @@ const autoland = require('../lib/autoland');
|
|
|
9
9
|
const { gateForHuman, plainLandingReason } = require('../lib/voice-gate');
|
|
10
10
|
const { evaluateAutoAccept } = require('../lib/auto-accept-certified');
|
|
11
11
|
const { sweepEngineAskReceipts } = require('../lib/engine-receipt-sweep');
|
|
12
|
+
const { validateRecentAskReceipts } = require('../lib/engine-validate');
|
|
12
13
|
const { operatorReady, hasAgentJargon, explainResult } = autoland;
|
|
13
14
|
const MISSION_AUTO_VERIFY_STATUSES = new Set(['planning', 'paused', 'ready']);
|
|
14
15
|
const CLOSED_TASK_STATUSES = new Set(['done', 'archived']);
|
|
@@ -640,7 +641,7 @@ function pidAlive(pid) {
|
|
|
640
641
|
}
|
|
641
642
|
}
|
|
642
643
|
|
|
643
|
-
function runTick(root, args) {
|
|
644
|
+
async function runTick(root, args) {
|
|
644
645
|
const json = args.includes('--json');
|
|
645
646
|
const policy = autoland.readPolicy(root);
|
|
646
647
|
const receipt = { at: new Date().toISOString(), landed: [], alarms: 0, digest_due: false, digest_sent: false, enabled: Boolean(policy && policy.enabled) };
|
|
@@ -670,7 +671,7 @@ function runTick(root, args) {
|
|
|
670
671
|
fs.writeFileSync(lockPath, JSON.stringify({ pid: process.pid, at: Date.now() }));
|
|
671
672
|
} catch {}
|
|
672
673
|
try {
|
|
673
|
-
return runTickBody(root, { json, policy, receipt });
|
|
674
|
+
return await runTickBody(root, { json, policy, receipt });
|
|
674
675
|
} finally {
|
|
675
676
|
try { fs.unlinkSync(lockPath); } catch {}
|
|
676
677
|
}
|
|
@@ -720,7 +721,22 @@ function engineReceiptSweepNote(receipt) {
|
|
|
720
721
|
return `, finalized ${finalized} stale engine receipt${finalized === 1 ? '' : 's'} as presumed dead`;
|
|
721
722
|
}
|
|
722
723
|
|
|
723
|
-
function
|
|
724
|
+
async function runEngineAnswerValidation(root, receipt, deps = {}) {
|
|
725
|
+
try {
|
|
726
|
+
receipt.engine_answer_validation = await validateRecentAskReceipts(root, deps);
|
|
727
|
+
} catch (err) {
|
|
728
|
+
receipt.engine_answer_validation_error = String((err && err.message) || err).slice(0, 200);
|
|
729
|
+
}
|
|
730
|
+
return receipt.engine_answer_validation || null;
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
function engineAnswerValidationLine(receipt) {
|
|
734
|
+
const graded = Number(receipt.engine_answer_validation?.graded_answers) || 0;
|
|
735
|
+
if (!graded) return '';
|
|
736
|
+
return `graded ${graded} engine answer${graded === 1 ? '' : 's'}, scoreboard updated`;
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
async function runTickBody(root, { json, policy, receipt, engineValidationDeps = {} }) {
|
|
724
740
|
|
|
725
741
|
try {
|
|
726
742
|
receipt.engine_receipt_sweep = sweepEngineAskReceipts(root);
|
|
@@ -728,6 +744,8 @@ function runTickBody(root, { json, policy, receipt }) {
|
|
|
728
744
|
receipt.engine_receipt_sweep_error = String((err && err.message) || err).slice(0, 200);
|
|
729
745
|
}
|
|
730
746
|
|
|
747
|
+
await runEngineAnswerValidation(root, receipt, engineValidationDeps);
|
|
748
|
+
|
|
731
749
|
// 1. certify and land in one task process. Keeping both phases together lets
|
|
732
750
|
// the landing gate reuse the live certification verifier result without
|
|
733
751
|
// persisting trust across heartbeats. Denied lanes and check-less proofs wait.
|
|
@@ -1004,6 +1022,8 @@ function runTickBody(root, { json, policy, receipt }) {
|
|
|
1004
1022
|
// gate and still did not land — that is the shape of a stuck loop.
|
|
1005
1023
|
const stuckNote = stuckBacklogNote(receipt);
|
|
1006
1024
|
const summary = `autoland tick: ${receipt.reviews_certified ?? 0} reviews certified, ${receipt.landed.length} landed${receipt.landed.length ? ` (${receipt.landed.join(', ')})` : ''}, ${receipt.alarms} alarms${stuckNote}, digest ${digestTickStatus(receipt)}${reapNote}${janitorNote}${heldNote}${wishNote}${engineSweepNote}${receiptNote}`;
|
|
1025
|
+
const validationLine = engineAnswerValidationLine(receipt);
|
|
1026
|
+
if (validationLine) console.log(validationLine);
|
|
1007
1027
|
console.log(gateForHuman(summary).text);
|
|
1008
1028
|
for (const fulfilled of receipt.wish_dispatch?.fulfilled_results || []) {
|
|
1009
1029
|
if (fulfilled.review_ask) console.log(fulfilled.review_ask);
|
|
@@ -1064,10 +1084,12 @@ module.exports = {
|
|
|
1064
1084
|
digestNextMoves,
|
|
1065
1085
|
digestStoryRows,
|
|
1066
1086
|
digestTickStatus,
|
|
1087
|
+
engineAnswerValidationLine,
|
|
1067
1088
|
explainResult,
|
|
1068
1089
|
operatorReady,
|
|
1069
1090
|
readAcceptedTaskHistory,
|
|
1070
1091
|
hasAgentJargon,
|
|
1092
|
+
runEngineAnswerValidation,
|
|
1071
1093
|
runTickBody,
|
|
1072
1094
|
sweepLanding,
|
|
1073
1095
|
verifyClosedTaskMissions,
|
package/commands/brain.js
CHANGED
|
@@ -5,6 +5,11 @@ const { spawnSync } = require('child_process');
|
|
|
5
5
|
const { refreshNowFile } = require('./now');
|
|
6
6
|
const escapeRegExp = require('../lib/escape-regexp');
|
|
7
7
|
const { hasRenderedSections, isOpenSection, isDoneSection } = require('../lib/todo-sections');
|
|
8
|
+
const {
|
|
9
|
+
renderVoiceCardBlock,
|
|
10
|
+
upsertCursorVoiceCard,
|
|
11
|
+
voiceCardForRoot,
|
|
12
|
+
} = require('../lib/voice-card');
|
|
8
13
|
|
|
9
14
|
const GENERATED_START = '<!-- ATRIS_BRAIN_COMPILE:START -->';
|
|
10
15
|
const GENERATED_END = '<!-- ATRIS_BRAIN_COMPILE:END -->';
|
|
@@ -1424,7 +1429,7 @@ ${nextMove(state)}
|
|
|
1424
1429
|
`;
|
|
1425
1430
|
}
|
|
1426
1431
|
|
|
1427
|
-
function generatedBootBlock(state) {
|
|
1432
|
+
function generatedBootBlock(state, voiceCard = voiceCardForRoot(state.root)) {
|
|
1428
1433
|
return `${GENERATED_START}
|
|
1429
1434
|
## Atris Brain Compile
|
|
1430
1435
|
|
|
@@ -1441,6 +1446,9 @@ Purpose: optimize for decision-speed; lead with the move, then use descriptions
|
|
|
1441
1446
|
Shape: \`<operator>, today is about <move>\` -> \`I picked this because <why now>\` -> \`Ready: <draft/proof/context>\` -> \`Go deeper: <paths>\`.
|
|
1442
1447
|
Definitions: operator = current person or agent; move = one concrete high-leverage workflow; why now = business reason; ready = prepared action or proof; paths = 2-4 optional deeper views.
|
|
1443
1448
|
|
|
1449
|
+
Keep this voice beside every reply:
|
|
1450
|
+
${renderVoiceCardBlock(voiceCard)}
|
|
1451
|
+
|
|
1444
1452
|
Re-run after meaningful work:
|
|
1445
1453
|
\`atris brain compile --root .\`
|
|
1446
1454
|
${GENERATED_END}
|
|
@@ -1475,10 +1483,13 @@ function writeBrain(state) {
|
|
|
1475
1483
|
fs.writeFileSync(ledgerPath, renderLedger(state), 'utf8');
|
|
1476
1484
|
fs.writeFileSync(jsonPath, JSON.stringify(state, null, 2) + '\n', 'utf8');
|
|
1477
1485
|
|
|
1478
|
-
const
|
|
1486
|
+
const voiceCard = voiceCardForRoot(state.root);
|
|
1487
|
+
const bootBlock = generatedBootBlock(state, voiceCard);
|
|
1479
1488
|
for (const fileName of ['AGENTS.md', 'CLAUDE.md', 'GEMINI.md']) {
|
|
1480
1489
|
upsertGeneratedBlock(path.join(state.root, fileName), fileName.replace(/\.md$/, ''), bootBlock);
|
|
1481
1490
|
}
|
|
1491
|
+
const cursorVoicePath = path.join(state.root, '.cursor', 'rules', 'atris-voice.mdc');
|
|
1492
|
+
upsertCursorVoiceCard(cursorVoicePath, voiceCard);
|
|
1482
1493
|
|
|
1483
1494
|
const wikiStatusPath = path.join(state.root, 'atris', 'wiki', 'STATUS.md');
|
|
1484
1495
|
if (fs.existsSync(wikiStatusPath)) {
|
|
@@ -1495,7 +1506,7 @@ function writeBrain(state) {
|
|
|
1495
1506
|
`);
|
|
1496
1507
|
}
|
|
1497
1508
|
|
|
1498
|
-
return { statusPath, ledgerPath, jsonPath };
|
|
1509
|
+
return { statusPath, ledgerPath, jsonPath, cursorVoicePath };
|
|
1499
1510
|
}
|
|
1500
1511
|
|
|
1501
1512
|
function verifyBrain(root) {
|
package/commands/ci.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
formatUsageSummary,
|
|
5
|
+
parseRunnerArgs,
|
|
6
|
+
parseUsageArgs,
|
|
7
|
+
readUsageRecords,
|
|
8
|
+
runCiRunner,
|
|
9
|
+
summarizeUsage,
|
|
10
|
+
usageFilePath,
|
|
11
|
+
} = require('../lib/ci-runner');
|
|
12
|
+
|
|
13
|
+
function showCiHelp() {
|
|
14
|
+
console.log('atris ci runs github actions jobs on this machine with a warm local work folder.');
|
|
15
|
+
console.log('change runs-on: ubuntu-latest to runs-on: atris.');
|
|
16
|
+
console.log('a GITHUB_TOKEN or an authenticated gh cli is required.');
|
|
17
|
+
console.log('usage: atris ci runner --repo <owner/name> [--label <name>] [--once]');
|
|
18
|
+
console.log(' atris ci usage [--repo <owner/name>]');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async function ciCommand(argv, dependencies = {}) {
|
|
22
|
+
if (argv.length === 0 || argv[0] === 'help' || argv.includes('--help') || argv.includes('-h')) {
|
|
23
|
+
showCiHelp();
|
|
24
|
+
return 0;
|
|
25
|
+
}
|
|
26
|
+
if (argv[0] === 'usage') {
|
|
27
|
+
const options = parseUsageArgs(argv.slice(1));
|
|
28
|
+
const records = (dependencies.readUsageRecords || readUsageRecords)(
|
|
29
|
+
dependencies.usagePath || usageFilePath(),
|
|
30
|
+
dependencies.readFile,
|
|
31
|
+
);
|
|
32
|
+
const clock = dependencies.clock || (() => new Date());
|
|
33
|
+
const log = dependencies.log || console.log;
|
|
34
|
+
log(formatUsageSummary(summarizeUsage(records, { ...options, now: clock() })));
|
|
35
|
+
return 0;
|
|
36
|
+
}
|
|
37
|
+
if (argv[0] === 'runner') {
|
|
38
|
+
await runCiRunner(parseRunnerArgs(argv.slice(1)), dependencies);
|
|
39
|
+
return 0;
|
|
40
|
+
}
|
|
41
|
+
throw new Error(`unknown ci subcommand: ${argv[0]}`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
module.exports = { ciCommand, showCiHelp };
|