@ours.network/fleet 1.2.0-nightly.36 → 1.2.0-nightly.37
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/dist/build-info.json +4 -4
- package/dist/harness/claude-code.js +9 -1
- package/dist/harness/claude-runtime.d.ts +12 -0
- package/dist/harness/claude-runtime.js +43 -0
- package/dist/init-wizard.d.ts +2 -0
- package/dist/init-wizard.js +16 -9
- package/dist/preset-migration.js +10 -0
- package/dist/session/acp.d.ts +4 -1
- package/dist/session/acp.js +7 -6
- package/dist/session/codex-app-server.js +1 -2
- package/dist/web/server.js +6 -2
- package/package.json +1 -1
- package/presets/fleet/roles/Coordinator.yaml +12 -17
- package/presets/manifest.json +1 -1
package/dist/build-info.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.2.0-nightly.
|
|
3
|
-
"buildId": "
|
|
4
|
-
"commit": "
|
|
2
|
+
"version": "1.2.0-nightly.37",
|
|
3
|
+
"buildId": "4ab0c90048fe",
|
|
4
|
+
"commit": "46569b7ed2c22fd25fd6a019a3755768c817046e",
|
|
5
5
|
"dirty": true,
|
|
6
|
-
"builtAt": "2026-10-
|
|
6
|
+
"builtAt": "2026-10-02T21:13:43.143Z",
|
|
7
7
|
"capabilities": [
|
|
8
8
|
"workspace.enroll.preserve-profile-v1",
|
|
9
9
|
"cowork.http-management-v1",
|
|
@@ -6,7 +6,8 @@ import { realExec } from '../exec.js';
|
|
|
6
6
|
import { registerAdapter } from './registry.js';
|
|
7
7
|
import { replaceFileAtomically, withFileLock } from '../atomic-file.js';
|
|
8
8
|
import { harnessRuntimeDir } from '../isolation/policy.js';
|
|
9
|
-
import { bundledAcpAgent } from './acp-agent.js';
|
|
9
|
+
import { bundledAcpAgent, resolveBundledAcpAgent } from './acp-agent.js';
|
|
10
|
+
import { hostClaude } from './claude-runtime.js';
|
|
10
11
|
import { ClaudeCodeAgentSessionAdapter } from './claude-code-session.js';
|
|
11
12
|
const OPTION_KEYS = [
|
|
12
13
|
'plugins', 'mem_palace', 'mem_palace_midsession_autosave', 'permission_mode', 'effort',
|
|
@@ -283,6 +284,13 @@ export function makeClaudeCodeAdapter(exec = realExec, transport) {
|
|
|
283
284
|
};
|
|
284
285
|
if (!memPalace)
|
|
285
286
|
env.MEMPALACE_DISABLED = 'true';
|
|
287
|
+
// The bundled adapter runs the Claude Code shipped with its SDK unless told otherwise. A host
|
|
288
|
+
// Claude Code at least as new as that copy is the one the person updates, so sessions run it.
|
|
289
|
+
if (!customAcpCommand(role)) {
|
|
290
|
+
const host = hostClaude(resolveBundledAcpAgent('@agentclientprotocol/claude-agent-acp', 'claude-agent-acp', 'claude-agent-acp').manifestPath, { ...process.env, ...role.env }, dirs.runCwd);
|
|
291
|
+
if (host)
|
|
292
|
+
env.CLAUDE_CODE_EXECUTABLE = host.path;
|
|
293
|
+
}
|
|
286
294
|
// Per-role harness runtime home. Created before sandbox entry so the
|
|
287
295
|
// bind has something to mount; harmless for un-isolated roles.
|
|
288
296
|
// Only a role that declares `isolation:` gets a sandbox, and only a
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** The Claude Code version shipped inside the adapter's own SDK dependency. */
|
|
2
|
+
export declare function bundledClaudeVersion(adapterManifest: string): string | undefined;
|
|
3
|
+
/**
|
|
4
|
+
* The host's own Claude Code, when ACP sessions should run it instead of the copy bundled with the adapter.
|
|
5
|
+
* The person signs in to, updates and checks the host Claude Code, and a newer one knows models the bundled
|
|
6
|
+
* one does not. It is used only when it is at least as new as the bundled copy; an explicit
|
|
7
|
+
* CLAUDE_CODE_EXECUTABLE, in the role or the service environment, always decides instead.
|
|
8
|
+
*/
|
|
9
|
+
export declare function hostClaude(adapterManifest: string | undefined, env: NodeJS.ProcessEnv, cwd?: string, version?: (path: string, env: NodeJS.ProcessEnv) => string | undefined): {
|
|
10
|
+
path: string;
|
|
11
|
+
version: string;
|
|
12
|
+
} | undefined;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
import { dirname, join } from 'node:path';
|
|
4
|
+
import { spawnSync } from 'node:child_process';
|
|
5
|
+
import { codexVersionAtLeast, executableOnPath } from './codex-runtime.js';
|
|
6
|
+
const versionOf = (text) => text.match(/\b(\d+\.\d+\.\d+)\b/)?.[1];
|
|
7
|
+
function installedClaudeVersion(path, env) {
|
|
8
|
+
const result = spawnSync(path, ['--version'], { env, encoding: 'utf8', timeout: 5_000, stdio: ['ignore', 'pipe', 'ignore'] });
|
|
9
|
+
return result.status === 0 ? versionOf(result.stdout ?? '') : undefined;
|
|
10
|
+
}
|
|
11
|
+
/** The Claude Code version shipped inside the adapter's own SDK dependency. */
|
|
12
|
+
export function bundledClaudeVersion(adapterManifest) {
|
|
13
|
+
try {
|
|
14
|
+
const sdk = dirname(createRequire(adapterManifest).resolve('@anthropic-ai/claude-agent-sdk'));
|
|
15
|
+
const version = JSON.parse(readFileSync(join(sdk, 'package.json'), 'utf8')).claudeCodeVersion;
|
|
16
|
+
return typeof version === 'string' ? version : undefined;
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The host's own Claude Code, when ACP sessions should run it instead of the copy bundled with the adapter.
|
|
24
|
+
* The person signs in to, updates and checks the host Claude Code, and a newer one knows models the bundled
|
|
25
|
+
* one does not. It is used only when it is at least as new as the bundled copy; an explicit
|
|
26
|
+
* CLAUDE_CODE_EXECUTABLE, in the role or the service environment, always decides instead.
|
|
27
|
+
*/
|
|
28
|
+
export function hostClaude(adapterManifest, env, cwd = process.cwd(), version = installedClaudeVersion) {
|
|
29
|
+
if (env.CLAUDE_CODE_EXECUTABLE !== undefined || !adapterManifest)
|
|
30
|
+
return undefined;
|
|
31
|
+
const bundled = bundledClaudeVersion(adapterManifest);
|
|
32
|
+
if (!bundled)
|
|
33
|
+
return undefined;
|
|
34
|
+
let path;
|
|
35
|
+
try {
|
|
36
|
+
path = executableOnPath('claude', env, cwd);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
const found = version(path, env);
|
|
42
|
+
return found && codexVersionAtLeast(found, bundled) ? { path, version: found } : undefined;
|
|
43
|
+
}
|
package/dist/init-wizard.d.ts
CHANGED
|
@@ -53,6 +53,8 @@ export declare function validateCatalog(value: BrainCatalog, path?: string): Bra
|
|
|
53
53
|
export declare function readInitSettings(path: string): InitAnswers;
|
|
54
54
|
export declare function askInitQuestions(prompter: InitPrompter, configuration: string): Promise<InitAnswers | undefined>;
|
|
55
55
|
export declare function formatSetupSummary(answers: InitAnswers, configuration: string): string;
|
|
56
|
+
/** The packaged Brain preset for a catalog model at one effort; the same naming the presets are generated with. */
|
|
57
|
+
export declare function brainPresetId(model: Pick<CatalogModel, 'harness' | 'model'>, effort: string): string;
|
|
56
58
|
/** Build the exact, deterministic default experience without writing to disk. */
|
|
57
59
|
export declare function generateSetup(answers: InitAnswers): GeneratedSetup;
|
|
58
60
|
/** Run the mutation boundary only after the complete questionnaire is accepted. */
|
package/dist/init-wizard.js
CHANGED
|
@@ -173,6 +173,7 @@ export function formatSetupSummary(answers, configuration) {
|
|
|
173
173
|
' Team: LocalCoordinator + Developer + Critic',
|
|
174
174
|
' Gated engineering: Engineer (gate pipeline) + independent Critic',
|
|
175
175
|
' FleetCoordinator: coordination model',
|
|
176
|
+
' Brains: the packaged presets; each prepared agent references the preset of its chosen model',
|
|
176
177
|
'',
|
|
177
178
|
'After the final Yes, Fleet performs host service setup before publishing the complete configuration.',
|
|
178
179
|
'A hard termination after that Yes can leave host integration or private stage/recovery evidence to inspect.',
|
|
@@ -181,6 +182,11 @@ export function formatSetupSummary(answers, configuration) {
|
|
|
181
182
|
function preset(relative) {
|
|
182
183
|
return readFileSync(join(packagedPresetRoot(), 'fleet', relative), 'utf8');
|
|
183
184
|
}
|
|
185
|
+
/** The packaged Brain preset for a catalog model at one effort; the same naming the presets are generated with. */
|
|
186
|
+
export function brainPresetId(model, effort) {
|
|
187
|
+
return `${model.harness === 'claude-code' ? 'claude' : 'codex'}-${model.model
|
|
188
|
+
.replace(/^claude-/, '').replace(/\./g, '-').toLowerCase()}-${effort}`;
|
|
189
|
+
}
|
|
184
190
|
/** Build the exact, deterministic default experience without writing to disk. */
|
|
185
191
|
export function generateSetup(answers) {
|
|
186
192
|
const effort = REASONING_EFFORT[answers.reasoning];
|
|
@@ -201,6 +207,7 @@ export function generateSetup(answers) {
|
|
|
201
207
|
' permissions: { approval: ask, filesystem: workspace, unattended: deny }',
|
|
202
208
|
'',
|
|
203
209
|
].join('\n'));
|
|
210
|
+
const assigned = {};
|
|
204
211
|
for (const work of WORK_KINDS) {
|
|
205
212
|
const proposed = answers.models[work];
|
|
206
213
|
if (!proposed || !answers.subscriptions.includes(subscriptionFor(proposed)))
|
|
@@ -214,14 +221,14 @@ export function generateSetup(answers) {
|
|
|
214
221
|
throw new Error(`${work} contains tampered model capabilities`);
|
|
215
222
|
if (!model.efforts.includes(effort))
|
|
216
223
|
throw new Error(`${MODEL_LABELS[model.model]} does not support ${answers.reasoning} reasoning`);
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
`
|
|
221
|
-
|
|
222
|
-
'',
|
|
223
|
-
].join('\n'));
|
|
224
|
+
// The chosen model is assigned by reference to its packaged Brain preset; setup defines no Brain of its own.
|
|
225
|
+
const id = brainPresetId(model, effort);
|
|
226
|
+
if (!existsSync(join(packagedPresetRoot(), 'fleet', 'brains', `${id}.yaml`)))
|
|
227
|
+
throw new Error(`no packaged Brain preset for ${MODEL_LABELS[model.model]} at ${effort} reasoning`);
|
|
228
|
+
assigned[work] = id;
|
|
224
229
|
}
|
|
230
|
+
for (const name of readdirSync(join(packagedPresetRoot(), 'fleet', 'brains')).filter(name => name.endsWith('.yaml')).sort())
|
|
231
|
+
files.set(`brains/${name}`, preset(`brains/${name}`));
|
|
225
232
|
if (answers.assignmentStrategy === 'one-model') {
|
|
226
233
|
const tuples = new Set(WORK_KINDS.map(work => {
|
|
227
234
|
const model = answers.models[work];
|
|
@@ -236,7 +243,7 @@ export function generateSetup(answers) {
|
|
|
236
243
|
continue;
|
|
237
244
|
files.set(`agent_templates/${role}.yaml`, [
|
|
238
245
|
`role: { ref: ${role} }`,
|
|
239
|
-
`brain: { ref: ${ROLE_WORK[role]} }`,
|
|
246
|
+
`brain: { ref: ${assigned[ROLE_WORK[role]]} }`,
|
|
240
247
|
'coordinator: FleetCoordinator',
|
|
241
248
|
// Temporary default while the product is being tested: prepared agents work without asking.
|
|
242
249
|
'permissions: { approval: allow, filesystem: unrestricted, unattended: deny }',
|
|
@@ -245,7 +252,7 @@ export function generateSetup(answers) {
|
|
|
245
252
|
].join('\n'));
|
|
246
253
|
}
|
|
247
254
|
files.set('agents/FleetCoordinator.yaml', preset('agents/FleetCoordinator.yaml')
|
|
248
|
-
.replace('brain: { ref: claude-default }',
|
|
255
|
+
.replace('brain: { ref: claude-default }', `brain: { ref: ${assigned.coordination} }`));
|
|
249
256
|
for (const name of ['single', 'pair', 'team', 'engineering']) {
|
|
250
257
|
files.set(`room_templates/${name}.yaml`, preset(`room_templates/${name}.yaml`));
|
|
251
258
|
files.set(`room_layouts/${name}.yaml`, preset(`room_layouts/${name}.yaml`));
|
package/dist/preset-migration.js
CHANGED
|
@@ -67,6 +67,14 @@ const V5_GENERATED_ROLE_DEFAULT_FINGERPRINTS = Object.freeze({
|
|
|
67
67
|
'agent_templates/Developer.yaml': 'fdd953aab72d042e62780dd273598745aae59521b39edf4876d7676bb7189c83',
|
|
68
68
|
'agent_templates/Critic.yaml': '3e98a28f17876061cfadf984351aa59fdbe19629e514eff52c74546545c64a91',
|
|
69
69
|
});
|
|
70
|
+
// The packaged Coordinator role of revisions 8 and 9 addressed a named owner channel that a
|
|
71
|
+
// fresh installation does not have. Untouched copies adopt the current role; edited ones stay.
|
|
72
|
+
const OWNER_CHANNEL_COORDINATOR_FINGERPRINTS = Object.freeze({
|
|
73
|
+
'roles/Coordinator.yaml': [
|
|
74
|
+
'8c8ad28d9bb9ddf9dba8c5c9c7859f25edd8fa10ebf833e2340124a6e49583ec',
|
|
75
|
+
'f0d8b169ad0a18051b57e5280b93cf01e05faa5c12f4e12bdf89973edf2ef58a',
|
|
76
|
+
],
|
|
77
|
+
});
|
|
70
78
|
const CURRENT_ROLE_DEFAULTS = new Set([
|
|
71
79
|
'roles/Coordinator.yaml', 'roles/LocalCoordinator.yaml', 'roles/Developer.yaml', 'roles/Critic.yaml',
|
|
72
80
|
'roles/Engineer.yaml',
|
|
@@ -196,6 +204,7 @@ export function migratePackagedRoleDefaults(configuration, options = {}, hooks =
|
|
|
196
204
|
...Object.keys(V3_ROLE_DEFAULT_FINGERPRINTS),
|
|
197
205
|
...Object.keys(V4_ROLE_DEFAULT_FINGERPRINTS),
|
|
198
206
|
...Object.keys(V5_ROLE_DEFAULT_FINGERPRINTS),
|
|
207
|
+
...Object.keys(OWNER_CHANNEL_COORDINATOR_FINGERPRINTS),
|
|
199
208
|
]);
|
|
200
209
|
for (const relative of known) {
|
|
201
210
|
const path = join(root, relative);
|
|
@@ -209,6 +218,7 @@ export function migratePackagedRoleDefaults(configuration, options = {}, hooks =
|
|
|
209
218
|
V4_GENERATED_ROLE_DEFAULT_FINGERPRINTS[relative],
|
|
210
219
|
V5_ROLE_DEFAULT_FINGERPRINTS[relative],
|
|
211
220
|
V5_GENERATED_ROLE_DEFAULT_FINGERPRINTS[relative],
|
|
221
|
+
...(OWNER_CHANNEL_COORDINATOR_FINGERPRINTS[relative] ?? []),
|
|
212
222
|
].some(expected => expected !== undefined && actual === expected);
|
|
213
223
|
if (recognized)
|
|
214
224
|
(CURRENT_ROLE_DEFAULTS.has(relative) ? replacements : removals).push(path);
|
package/dist/session/acp.d.ts
CHANGED
|
@@ -339,7 +339,10 @@ export declare class AcpSession implements AgentSession {
|
|
|
339
339
|
* signal. Never infer commentary from text, message order, or unknown meta.
|
|
340
340
|
*/
|
|
341
341
|
private codexMessagePhase;
|
|
342
|
-
/**
|
|
342
|
+
/**
|
|
343
|
+
* Normalize every ACP update losslessly into the durable ledger. The ledger is the conversation the
|
|
344
|
+
* owner reads, so the agent's commentary between its tools is kept as written, like its final answer.
|
|
345
|
+
*/
|
|
343
346
|
private recordConversationUpdate;
|
|
344
347
|
taskNoticeBinding(): TaskNoticeBinding | undefined;
|
|
345
348
|
recordTaskCreated(binding: TaskNoticeBinding, notice: TaskCreatedNotice): void;
|
package/dist/session/acp.js
CHANGED
|
@@ -38,7 +38,6 @@ const TERMINAL_TOOL_STATUSES = new Set(['completed', 'failed']);
|
|
|
38
38
|
/** Consumed only by Fleet's authenticated bundled-Codex app-server proxy. */
|
|
39
39
|
export const CODEX_DISABLE_INHERITED_MCP_ENV = 'OURS_FLEET_CODEX_DISABLE_INHERITED_MCP';
|
|
40
40
|
const SCHEDULED_LOOP_REDACTION = '[scheduled-loop content redacted]';
|
|
41
|
-
const OWNER_COMMENTARY_REDACTION = '[assistant commentary redacted]';
|
|
42
41
|
const MAX_CANONICAL_SYMLINK_DEPTH = 40;
|
|
43
42
|
const scheduledTurn = (turn) => turn?.origin?.kind === 'scheduled-loop';
|
|
44
43
|
/**
|
|
@@ -1711,7 +1710,7 @@ export class AcpSession {
|
|
|
1711
1710
|
const scheduled = this.activeTurn?.origin?.kind === 'scheduled-loop';
|
|
1712
1711
|
const messagePhase = update.sessionUpdate === 'agent_message_chunk'
|
|
1713
1712
|
? this.codexMessagePhase(update) : undefined;
|
|
1714
|
-
this.recordConversationUpdate(update, scheduled
|
|
1713
|
+
this.recordConversationUpdate(update, scheduled);
|
|
1715
1714
|
if (update.sessionUpdate === 'config_option_update')
|
|
1716
1715
|
this.captureRuntimeMetadata(update.configOptions);
|
|
1717
1716
|
if (update.sessionUpdate === 'usage_update') {
|
|
@@ -1795,13 +1794,15 @@ export class AcpSession {
|
|
|
1795
1794
|
return undefined;
|
|
1796
1795
|
return phase === 'commentary' || phase === 'final_answer' ? phase : 'ambiguous';
|
|
1797
1796
|
}
|
|
1798
|
-
/**
|
|
1799
|
-
|
|
1797
|
+
/**
|
|
1798
|
+
* Normalize every ACP update losslessly into the durable ledger. The ledger is the conversation the
|
|
1799
|
+
* owner reads, so the agent's commentary between its tools is kept as written, like its final answer.
|
|
1800
|
+
*/
|
|
1801
|
+
recordConversationUpdate(update, scheduled) {
|
|
1800
1802
|
const normalized = normalizeSessionUpdate(update, scheduled ? {
|
|
1801
1803
|
redactText: SCHEDULED_LOOP_REDACTION,
|
|
1802
1804
|
redactToolCallId: 'scheduled-loop-tool',
|
|
1803
|
-
}
|
|
1804
|
-
: commentary ? { redactText: OWNER_COMMENTARY_REDACTION } : {});
|
|
1805
|
+
} : {});
|
|
1805
1806
|
this.conversation.appendSafe({
|
|
1806
1807
|
kind: normalized.kind,
|
|
1807
1808
|
sessionGeneration: this.sessionGeneration,
|
|
@@ -14,7 +14,6 @@ const INTERRUPT_TERMINATE_GRACE_MS = 5_000;
|
|
|
14
14
|
const TERMINAL_RECONCILE_QUIET_MS = 2_000;
|
|
15
15
|
const TERMINAL_RECONCILE_REQUEST_TIMEOUT_MS = 5_000;
|
|
16
16
|
const SCHEDULED_REDACTION = '[scheduled-loop content redacted]';
|
|
17
|
-
const COMMENTARY_REDACTION = '[assistant commentary redacted]';
|
|
18
17
|
const OWNER_ADMIN_CONTEXT_KEY = 'ours-fleet://prompt-provenance?source=owner_admin_console';
|
|
19
18
|
const OWNER_CHANNEL_CONTEXT_KEY = 'ours-fleet://prompt-provenance?source=owner_channel';
|
|
20
19
|
const isObject = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
@@ -719,7 +718,7 @@ export class CodexAppServerSession {
|
|
|
719
718
|
promptId: this.activeTurn?.promptId, turnId: this.activeTurn?.promptId,
|
|
720
719
|
messageId: id, source: 'agent',
|
|
721
720
|
payload: {
|
|
722
|
-
role: 'assistant', content: textBlock(delta, scheduled ? SCHEDULED_REDACTION :
|
|
721
|
+
role: 'assistant', content: textBlock(delta, scheduled ? SCHEDULED_REDACTION : undefined),
|
|
723
722
|
},
|
|
724
723
|
});
|
|
725
724
|
}
|
package/dist/web/server.js
CHANGED
|
@@ -202,9 +202,13 @@ export async function buildWebServer(services, boundary, options = {}) {
|
|
|
202
202
|
throw new FleetError('backend_failure', `Fleet setup did not complete: ${error.message}`);
|
|
203
203
|
}
|
|
204
204
|
// Setup preserves files it finds, so confirm the published models are the ones this request chose.
|
|
205
|
-
|
|
205
|
+
// The prepared agents reference packaged Brain presets, so resolve what each of them now points at:
|
|
206
|
+
// a preserved file of a packaged name may hold another model, session or reasoning than its name says.
|
|
207
|
+
const published = configuration.read(true).model, brains = published.brains ?? {};
|
|
208
|
+
const brainOf = (holder) => brains[String(holder?.brain?.ref ?? '')];
|
|
209
|
+
const assigned = { coordination: brainOf(published.agents.FleetCoordinator), development: brainOf(published.agent_templates?.Developer), review: brainOf(published.agent_templates?.Critic) };
|
|
206
210
|
for (const work of ONBOARDING_WORK)
|
|
207
|
-
if (
|
|
211
|
+
if (assigned[work]?.harness !== models[work].harness || assigned[work]?.model !== models[work].model || assigned[work]?.session !== models[work].session || assigned[work]?.effort !== 'medium')
|
|
208
212
|
throw new FleetError('conflict', 'Fleet was set up with different models; review its configuration');
|
|
209
213
|
return { configured: true };
|
|
210
214
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ours.network/fleet",
|
|
3
|
-
"version": "1.2.0-nightly.
|
|
3
|
+
"version": "1.2.0-nightly.37",
|
|
4
4
|
"description": "Harness-agnostic fleet of persistent, identity-bound AI agents. Declarative fleet.yaml, managed native/ACP sessions, supervision, and ours.network messaging.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "FSL-1.1-Apache-2.0",
|
|
@@ -2,16 +2,12 @@ mission: Keep fleet development moving by managing the task backlog, rooms, and
|
|
|
2
2
|
persona: |
|
|
3
3
|
You are the fleet Coordinator. Own progress and workflow, not execution quality or results.
|
|
4
4
|
|
|
5
|
-
Each time your session starts, before anything else,
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
how
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
Immediately before each meaningful action, proactively use ours `send_message` to contact
|
|
12
|
-
`Coordinator Owner Channel` with a short, plain one-sentence statement of what you are about to do.
|
|
13
|
-
This is an informational intent notice, never a permission request; proceed without waiting unless
|
|
14
|
-
a separate safety or authority rule genuinely requires approval.
|
|
5
|
+
Each time your session starts, before anything else, introduce yourself in your first reply in
|
|
6
|
+
this conversation, in two or three plain sentences: you are the Fleet Coordinator, you have
|
|
7
|
+
started and are ready, and the owner can ask you anything about the fleet: how the app works, and
|
|
8
|
+
how to set up new agents, tasks and rooms. Do this once per start; it is not a permission request
|
|
9
|
+
and needs no reply. The owner reads this conversation: do not send the introduction, or any other
|
|
10
|
+
notice, to a separate contact or channel, and never report a missing contact or channel as a blocker.
|
|
15
11
|
|
|
16
12
|
Out of scope: do not personally implement, inspect, analyze, research, review, test, validate,
|
|
17
13
|
or otherwise execute task work. Delegate all execution to temporary agents in managed rooms.
|
|
@@ -43,13 +39,12 @@ persona: |
|
|
|
43
39
|
For every new task:
|
|
44
40
|
1. Record it first with `ours-fleet task create --title "<title>" --brief "<brief>" --backlog --no-room`.
|
|
45
41
|
2. Ask the owner which room template to use: `single`, `pair`, or `team`.
|
|
46
|
-
3. Resolve the exact launch plan without creating the room. Immediately before room creation,
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
4. Only after confirmed delivery, start it with
|
|
42
|
+
3. Resolve the exact launch plan without creating the room. Immediately before room creation,
|
|
43
|
+
state in this conversation that you are about to create the room, listing the task, selected
|
|
44
|
+
template, every member role and count, and each member's Agent Template,
|
|
45
|
+
Brain, harness, session, model, reasoning effort, permissions, and working directory.
|
|
46
|
+
This is a notice, not a permission request; do not wait for a reply.
|
|
47
|
+
4. Then start it with
|
|
53
48
|
`ours-fleet task start <task-id> --template <template>`.
|
|
54
49
|
|
|
55
50
|
Keep the backlog current with `ours-fleet task list --state all` and use `task show`, `task block`,
|