refactor(v2): per-group filesystem init, persistent across spawns
Each group's on-disk state (CLAUDE.md, .claude-shared/, agent-runner-src/) is now initialized exactly once at group creation and owned by the group forever after. Spawn does only mounts — no copies, no settings.json overwrites, no skill clobbers, no source resyncs. Global memory composition switches from "host reads /workspace/global/CLAUDE.md at bootstrap and stuffs it into systemPrompt.append" to "group CLAUDE.md imports it via @/workspace/global/CLAUDE.md at the top." Edits to global propagate instantly through the existing read-only mount; no copy, no restart. - src/group-init.ts: new initGroupFilesystem(group, opts?) — idempotent, populates groups/<folder>/, .claude-shared/, agent-runner-src/ only when paths don't already exist. - src/container-runner.ts: buildMounts() calls init defensively at the top (catches existing groups on first spawn after this change), drops the inline settings.json write, skills cpSync loop, and agent-runner-src rm-then-copy. Just mounts now. - src/delivery.ts: create_agent flow uses initGroupFilesystem with optional instructions, replacing the inline mkdirSync + writeFileSync. - container/agent-runner/src/index.ts: drops GLOBAL_CLAUDE_MD reading. systemContext.instructions is now only the runtime-generated destinations addendum. - scripts/migrate-group-claude-md.ts: one-shot migration that prepends the @-import to existing groups' CLAUDE.md. Skips if global doesn't exist or if the @-import is already present (regex match on the @ form to avoid false positives from prose mentions of the path). - groups/main/CLAUDE.md: prepended by the migration. Existing groups need a one-time wipe of their agent-runner-src/ dir so init re-populates from current host source — done locally before this commit. Future host-side updates to container/skills/ or container/agent-runner/src/ won't auto-propagate; that's the trade-off for unconditional persistence and will be covered by host-mediated refresh tools in a follow-up. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -51,8 +51,9 @@ import {
|
||||
writeSystemResponse,
|
||||
} from './session-manager.js';
|
||||
import { resetContainerIdleTimer, wakeContainer } from './container-runner.js';
|
||||
import { initGroupFilesystem } from './group-init.js';
|
||||
import type { OutboundFile } from './channels/adapter.js';
|
||||
import type { Session } from './types.js';
|
||||
import type { AgentGroup, Session } from './types.js';
|
||||
|
||||
const ACTIVE_POLL_MS = 1000;
|
||||
const SWEEP_POLL_MS = 60_000;
|
||||
@@ -509,7 +510,7 @@ async function handleSystemAction(
|
||||
const agentGroupId = `ag-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
||||
const now = new Date().toISOString();
|
||||
|
||||
createAgentGroup({
|
||||
const newGroup: AgentGroup = {
|
||||
id: agentGroupId,
|
||||
name,
|
||||
folder,
|
||||
@@ -517,12 +518,9 @@ async function handleSystemAction(
|
||||
agent_provider: null,
|
||||
container_config: null,
|
||||
created_at: now,
|
||||
});
|
||||
|
||||
fs.mkdirSync(groupPath, { recursive: true });
|
||||
if (instructions) {
|
||||
fs.writeFileSync(path.join(groupPath, 'CLAUDE.md'), instructions);
|
||||
}
|
||||
};
|
||||
createAgentGroup(newGroup);
|
||||
initGroupFilesystem(newGroup, { instructions: instructions ?? undefined });
|
||||
|
||||
// Insert bidirectional destination rows (= ACL grants).
|
||||
// Creator refers to child by the name it chose; child refers to creator as "parent".
|
||||
|
||||
Reference in New Issue
Block a user