diff --git a/.claude/agents/architect.md b/.claude/agents/architect.md index 5be684b..76081f8 100644 --- a/.claude/agents/architect.md +++ b/.claude/agents/architect.md @@ -1,4 +1,5 @@ --- +name: architect description: Refine work into clear, independent units before implementation. --- diff --git a/.claude/agents/dev.md b/.claude/agents/dev.md index c336bee..21c5095 100644 --- a/.claude/agents/dev.md +++ b/.claude/agents/dev.md @@ -1,4 +1,5 @@ --- +name: dev description: Implement one assigned unit, test it, and open a pull request. --- diff --git a/.claude/agents/reviewer.md b/.claude/agents/reviewer.md index 1c0162a..d4fdd1a 100644 --- a/.claude/agents/reviewer.md +++ b/.claude/agents/reviewer.md @@ -1,4 +1,5 @@ --- +name: reviewer description: Review one assigned scope and report the most important real issue. --- diff --git a/bridged/src/main/java/dev/ltms/bridged/member/ClaudeCodeLauncher.java b/bridged/src/main/java/dev/ltms/bridged/member/ClaudeCodeLauncher.java index 2d190d7..f1e196e 100644 --- a/bridged/src/main/java/dev/ltms/bridged/member/ClaudeCodeLauncher.java +++ b/bridged/src/main/java/dev/ltms/bridged/member/ClaudeCodeLauncher.java @@ -279,9 +279,15 @@ public final class ClaudeCodeLauncher extends HerdrPeerLauncher { * single inline argv element — herdr refuses to shell-encode a multi-line argument * ({@code invalid_agent_argument}). It is written to a temp file instead and mounted with * {@code --append-system-prompt-file}, which this host confirms Claude Code accepts for a - * multi-line file. The reply charter is always exactly one line and demonstrably encodes, and it - * must reach a member with no repo checkout (nowhere to put a file), so it keeps its inline - * {@code --append-system-prompt} delivery. + * multi-line file. + * + *
CB-618: Claude Code refuses to start when BOTH {@code --append-system-prompt} and
+ * {@code --append-system-prompt-file} are on the command line ("Cannot use both ... Please use
+ * only one"), so the two charters can never travel on separate flags. When both are present they
+ * are concatenated into the one file, role charter first and reply charter last — last is where
+ * the reply rule must sit, because it is the rule that must survive. When only the reply charter
+ * is present it keeps its proven inline {@code --append-system-prompt} delivery, which is also
+ * the only form that reaches a member with no repo checkout.
*/
private List CB-618: and Claude Code itself refuses to start when both {@code --append-system-prompt} and
+ * {@code --append-system-prompt-file} are given ("Cannot use both ... Please use only one"), so
+ * the reply charter cannot ride inline alongside a role charter either. Both go in the one file,
+ * reply charter last. This drives the real launcher entry point ({@code spawn}), the same path a
+ * live spawn takes — not the argv builder in isolation.
*/
@Test
- void roleCharterTravelsByFileAndReplyCharterStaysInline() {
+ void bothChartersTravelInOneFileAndNeverOnBothFlags() {
FakeHerdr herdr = new FakeHerdr();
String roleCharter = "You review changes.\nLine two.\nLine three.";
BridgedConfig.Profile cfg = new BridgedConfig.Profile(
@@ -138,15 +143,15 @@ class ClaudeCodeLauncherTest {
int fileFlag = args.indexOf("--append-system-prompt-file");
assertTrue(fileFlag >= 0, "the role charter is mounted via --append-system-prompt-file: " + args);
+ assertFalse(args.contains("--append-system-prompt"),
+ "CB-618: Claude Code refuses to start with both flags — the reply charter must not "
+ + "ride inline beside a role charter: " + args);
assertDoesNotThrow(() -> {
String written = Files.readString(Path.of(args.get(fileFlag + 1)));
- assertEquals(roleCharter, written, "the file holds exactly the role charter text");
+ assertTrue(written.startsWith(roleCharter), "the file opens with the role charter: " + written);
+ assertTrue(written.endsWith(HerdrPeerLauncher.REPLY_CHARTER),
+ "the reply charter is last — it is the rule that must survive: " + written);
}, "the --append-system-prompt-file path must be a readable file");
-
- int inlineFlag = args.indexOf("--append-system-prompt");
- assertTrue(inlineFlag >= 0, "the reply charter still travels inline: " + args);
- assertEquals(HerdrPeerLauncher.REPLY_CHARTER, args.get(inlineFlag + 1),
- "only the reply charter (one line) rides inline — the role charter never does");
}
@Test