refactor: shared source — replace per-group agent-runner copies with single RO mount
Replace the per-group agent-runner-src copy model with a single shared read-only mount. Source and skills are now RO + shared; personality, config, working files, and Claude state stay RW + per-group. Key changes: - Mount container/agent-runner/src/ RO at /app/src (all groups share one copy) - Mount container/skills/ RO at /app/skills; per-group skill selection via symlinks in .claude-shared/skills/ based on container.json "skills" field - Mount container.json as nested RO bind on top of RW group dir - Move all NANOCLAW_* env vars to container.json (runner reads at startup) - New runner config.ts module replaces process.env reads - Move command gate (filtered/admin) from container to host router - Dockerfile: remove source COPY, split CLI installs (claude-code last), move agent-runner deps above CLIs for better layer caching - Add writeOutboundDirect for router denial responses - Design doc at docs/shared-src.md Not included (follow-up): DB migration to drop agent_provider columns, cleanup of orphaned agent-runner-src directories. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -37,12 +37,12 @@ const DEFAULT_SETTINGS_JSON =
|
||||
* an already-initialized group is a no-op.
|
||||
*
|
||||
* Called once per group lifetime: at creation, or defensively from
|
||||
* `buildMounts()` for groups that pre-date this code path. After init, the
|
||||
* host never overwrites any of these paths automatically — agents own them.
|
||||
* To pull in upstream changes, use the host-mediated reset/refresh tools.
|
||||
* `buildMounts()` for groups that pre-date this code path.
|
||||
*
|
||||
* Source code and skills are shared RO mounts — not copied per-group.
|
||||
* Skill symlinks are synced at spawn time by container-runner.ts.
|
||||
*/
|
||||
export function initGroupFilesystem(group: AgentGroup, opts?: { instructions?: string }): void {
|
||||
const projectRoot = process.cwd();
|
||||
const initialized: string[] = [];
|
||||
|
||||
// 1. groups/<folder>/ — group memory + working dir
|
||||
@@ -97,23 +97,12 @@ export function initGroupFilesystem(group: AgentGroup, opts?: { instructions?: s
|
||||
initialized.push('settings.json');
|
||||
}
|
||||
|
||||
// Skills directory — created empty here; symlinks are synced at spawn
|
||||
// time by container-runner.ts based on container.json skills selection.
|
||||
const skillsDst = path.join(claudeDir, 'skills');
|
||||
if (!fs.existsSync(skillsDst)) {
|
||||
const skillsSrc = path.join(projectRoot, 'container', 'skills');
|
||||
if (fs.existsSync(skillsSrc)) {
|
||||
fs.cpSync(skillsSrc, skillsDst, { recursive: true });
|
||||
initialized.push('skills/');
|
||||
}
|
||||
}
|
||||
|
||||
// 3. data/v2-sessions/<id>/agent-runner-src/ — per-group source copy
|
||||
const groupRunnerDir = path.join(DATA_DIR, 'v2-sessions', group.id, 'agent-runner-src');
|
||||
if (!fs.existsSync(groupRunnerDir)) {
|
||||
const agentRunnerSrc = path.join(projectRoot, 'container', 'agent-runner', 'src');
|
||||
if (fs.existsSync(agentRunnerSrc)) {
|
||||
fs.cpSync(agentRunnerSrc, groupRunnerDir, { recursive: true });
|
||||
initialized.push('agent-runner-src/');
|
||||
}
|
||||
fs.mkdirSync(skillsDst, { recursive: true });
|
||||
initialized.push('skills/');
|
||||
}
|
||||
|
||||
if (initialized.length > 0) {
|
||||
|
||||
Reference in New Issue
Block a user