@@ 265,6 265,49 @@ in
[ "$(cat $s/CLAUDE.md)" = edited ] || fail "user file modified"
'';
+ # A shared directory is a managed link to the other launcher's copy. The copy
+ # is created on demand, so the link works whichever launcher starts first, and
+ # undeclaring the share removes the link but never the data behind it.
+ shared-dirs =
+ let
+ withShare = share: {
+ claude.enable = true;
+ launchers.claude-work.agent = "claude";
+ launchers.claude-pers = {
+ agent = "claude";
+ sharedDirs = share;
+ };
+ };
+ sharing = mkEnvironment {
+ inherit pkgs;
+ modules = [
+ stubs
+ (withShare { projects = "claude-work"; })
+ ];
+ };
+ alone = mkEnvironment {
+ inherit pkgs;
+ modules = [
+ stubs
+ (withShare { })
+ ];
+ };
+ work = "$HOME/.local/agent-environments/claude-work";
+ pers = "$HOME/.local/agent-environments/claude-pers";
+ in
+ runTest "shared-dirs" ''
+ ${sharing.launchers.claude-pers}/bin/claude-pers
+ [ -d ${work}/projects ] || fail "shared target not created"
+ [ "$(readlink ${pers}/projects)" = ${work}/projects ] || fail "link: $(readlink ${pers}/projects)"
+ grep -qx projects ${pers}/.agent-environments-managed || fail "link not in manifest"
+ echo data >${pers}/projects/session.jsonl
+ [ "$(cat ${work}/projects/session.jsonl)" = data ] || fail "write did not land in the shared dir"
+
+ ${alone.launchers.claude-pers}/bin/claude-pers
+ [ ! -L ${pers}/projects ] || fail "undeclared share still linked"
+ [ "$(cat ${work}/projects/session.jsonl)" = data ] || fail "shared data removed with the link"
+ '';
+
# The launcher's own bookkeeping paths must not write through symlinks into
# files or directories outside the state dir.
no-writes-through-symlinks = runTest "no-writes-through-symlinks" ''
@@ 439,5 482,21 @@ in
src = skillSrc "x";
}).drvPath
).success;
+ # A shared dir must name another, existing launcher and a safe path component.
+ assert lib.all (share: fails [
+ stubs
+ {
+ claude.enable = true;
+ launchers.x.agent = "claude";
+ launchers.y = {
+ agent = "claude";
+ sharedDirs = share;
+ };
+ }
+ ]) [
+ { projects = "nope"; }
+ { projects = "y"; }
+ { "../escape" = "x"; }
+ ];
pkgs.runCommand "agent-environments-eval-errors" { } "touch $out";
}