@@ -349,6 +349,15 @@ pub struct CliArgs {
349349 /// Owner pubkey is always implicitly included.
350350 #[ arg( long, env = "SPROUT_ACP_RESPOND_TO_ALLOWLIST" , value_delimiter = ',' ) ]
351351 pub respond_to_allowlist : Option < Vec < String > > ,
352+
353+ /// Path to a persona pack directory. Used with --persona-name to configure
354+ /// the agent from a .persona.md pack instead of CLI flags.
355+ #[ arg( long, env = "SPROUT_ACP_PERSONA_PACK" ) ]
356+ pub persona_pack : Option < PathBuf > ,
357+
358+ /// Name of the persona within the pack to use. Required when --persona-pack is set.
359+ #[ arg( long, env = "SPROUT_ACP_PERSONA_NAME" ) ]
360+ pub persona_name : Option < String > ,
352361}
353362
354363// ── Merged NIP-01 filter ──────────────────────────────────────────────────────
@@ -400,6 +409,9 @@ pub struct Config {
400409 pub respond_to : RespondTo ,
401410 /// Validated allowlist of pubkey hex strings (used when respond_to == Allowlist).
402411 pub respond_to_allowlist : HashSet < String > ,
412+ /// Per-persona env vars to inject at agent spawn time (e.g., GOOSE_PROVIDER, GOOSE_MODEL).
413+ /// Populated from persona pack resolution. Empty when no pack is configured.
414+ pub persona_env_vars : Vec < ( String , String ) > ,
403415}
404416
405417/// Validate and deduplicate allowlist entries: each must be exactly 64 hex chars.
@@ -507,7 +519,7 @@ impl Config {
507519 . replace_range ( .., & "0" . repeat ( args. private_key . len ( ) ) ) ;
508520 args. private_key . clear ( ) ;
509521
510- let system_prompt = if let Some ( text) = args. system_prompt {
522+ let mut system_prompt = if let Some ( text) = args. system_prompt {
511523 Some ( text)
512524 } else if let Some ( ref path) = args. system_prompt_file {
513525 Some ( std:: fs:: read_to_string ( path) ?)
@@ -642,6 +654,54 @@ impl Config {
642654 HashSet :: new ( )
643655 } ;
644656
657+ // ── Persona pack resolution ──────────────────────────────────────────
658+ //
659+ // Precedence: CLI/env args > persona values > built-in defaults.
660+ // Persona fills in what's missing. Explicit flags always win.
661+ let ( persona_system_prompt, persona_model, persona_env_vars) =
662+ match ( & args. persona_pack , & args. persona_name ) {
663+ ( Some ( pack_dir) , Some ( name) ) => {
664+ let pack = sprout_persona:: resolve:: resolve_pack ( pack_dir) . map_err ( |e| {
665+ ConfigError :: ConfigFile ( format ! (
666+ "failed to resolve pack {}: {e}" ,
667+ pack_dir. display( )
668+ ) )
669+ } ) ?;
670+ let persona = pack
671+ . personas
672+ . into_iter ( )
673+ . find ( |p| p. name == * name)
674+ . ok_or_else ( || {
675+ ConfigError :: ConfigFile ( format ! (
676+ "persona '{name}' not found in pack {}" ,
677+ pack_dir. display( )
678+ ) )
679+ } ) ?;
680+ (
681+ Some ( persona. system_prompt ) ,
682+ persona. model ,
683+ persona. goose_env_vars ,
684+ )
685+ }
686+ ( Some ( _) , None ) => {
687+ return Err ( ConfigError :: ConfigFile (
688+ "--persona-pack requires --persona-name" . into ( ) ,
689+ ) ) ;
690+ }
691+ ( None , Some ( _) ) => {
692+ return Err ( ConfigError :: ConfigFile (
693+ "--persona-name requires --persona-pack" . into ( ) ,
694+ ) ) ;
695+ }
696+ ( None , None ) => ( None , None , vec ! [ ] ) ,
697+ } ;
698+
699+ // Apply persona defaults: CLI/env wins, persona fills gaps.
700+ if system_prompt. is_none ( ) {
701+ system_prompt = persona_system_prompt;
702+ }
703+ let model = args. model . or ( persona_model) ;
704+
645705 // ── Multiple-event-handling validation ──────────────────────────────
646706 if matches ! (
647707 args. multiple_event_handling,
@@ -682,10 +742,11 @@ impl Config {
682742 max_turns_per_session : args. max_turns_per_session ,
683743 presence_enabled : !args. no_presence ,
684744 typing_enabled : !args. no_typing ,
685- model : args . model ,
745+ model,
686746 permission_mode : args. permission_mode ,
687747 respond_to : args. respond_to ,
688748 respond_to_allowlist,
749+ persona_env_vars,
689750 } ;
690751
691752 Ok ( config)
@@ -1045,6 +1106,7 @@ mod tests {
10451106 permission_mode : PermissionMode :: BypassPermissions ,
10461107 respond_to : RespondTo :: Anyone ,
10471108 respond_to_allowlist : HashSet :: new ( ) ,
1109+ persona_env_vars : vec ! [ ] ,
10481110 }
10491111 }
10501112
0 commit comments