Add --profile flag for persistent browser profiles

Adds support for persistent browser profiles that preserve cookies,
localStorage, and login sessions across browser restarts.

Changes:
- Add --profile <path> CLI flag (flags.rs)
- Add AGENT_BROWSER_PROFILE environment variable support
- Add profile field to LaunchCommand type (types.ts)
- Use launchPersistentContext when profile is specified (browser.ts)
- Update help text and README with documentation

Usage:
  agent-browser --profile ~/.myapp-profile open myapp.com

This enables AI agents to maintain authenticated sessions across
browser restarts without re-authenticating each time.
This commit is contained in:
elsigh
2026-01-13 12:49:42 -08:00
parent 673e2e266e
commit d86de0e736
6 changed files with 68 additions and 7 deletions
+9 -1
View File
@@ -10,6 +10,7 @@ pub struct Flags {
pub executable_path: Option<String>,
pub cdp: Option<String>,
pub extensions: Vec<String>,
pub profile: Option<String>,
}
pub fn parse_flags(args: &[String]) -> Flags {
@@ -28,6 +29,7 @@ pub fn parse_flags(args: &[String]) -> Flags {
executable_path: env::var("AGENT_BROWSER_EXECUTABLE_PATH").ok(),
cdp: None,
extensions: extensions_env,
profile: env::var("AGENT_BROWSER_PROFILE").ok(),
};
let mut i = 0;
@@ -67,6 +69,12 @@ pub fn parse_flags(args: &[String]) -> Flags {
i += 1;
}
}
"--profile" => {
if let Some(s) = args.get(i + 1) {
flags.profile = Some(s.clone());
i += 1;
}
}
_ => {}
}
i += 1;
@@ -81,7 +89,7 @@ pub fn clean_args(args: &[String]) -> Vec<String> {
// Global flags that should be stripped from command args
const GLOBAL_FLAGS: &[&str] = &["--json", "--full", "--headed", "--debug"];
// Global flags that take a value (need to skip the next arg too)
const GLOBAL_FLAGS_WITH_VALUE: &[&str] = &["--session", "--headers", "--executable-path", "--cdp", "--extension"];
const GLOBAL_FLAGS_WITH_VALUE: &[&str] = &["--session", "--headers", "--executable-path", "--cdp", "--extension", "--profile"];
for arg in args.iter() {
if skip_next {
+15 -6
View File
@@ -161,8 +161,8 @@ fn main() {
}
};
// Warn if executable_path was specified but daemon was already running
if daemon_result.already_running && (flags.executable_path.is_some() || !flags.extensions.is_empty()) {
// Warn if executable_path, profile, or extensions were specified but daemon was already running
if daemon_result.already_running && (flags.executable_path.is_some() || !flags.extensions.is_empty() || flags.profile.is_some()) {
if !flags.json {
if flags.executable_path.is_some() {
eprintln!("\x1b[33m⚠\x1b[0m --executable-path ignored: daemon already running. Use 'agent-browser close' first to restart with new path.");
@@ -170,6 +170,9 @@ fn main() {
if !flags.extensions.is_empty() {
eprintln!("\x1b[33m⚠\x1b[0m --extension ignored: daemon already running. Use 'agent-browser close' first to restart with extensions.");
}
if flags.profile.is_some() {
eprintln!("\x1b[33m⚠\x1b[0m --profile ignored: daemon already running. Use 'agent-browser close' first to restart with profile.");
}
}
}
@@ -229,16 +232,22 @@ fn main() {
}
// Launch headed browser if --headed flag is set (without CDP)
if flags.headed && flags.cdp.is_none() {
let launch_cmd = json!({
// Also launch with profile if --profile is set
if (flags.headed || flags.profile.is_some()) && flags.cdp.is_none() {
let mut launch_cmd = json!({
"id": gen_id(),
"action": "launch",
"headless": false
"headless": !flags.headed
});
// Add profile path if specified
if let Some(ref profile_path) = flags.profile {
launch_cmd["profile"] = json!(profile_path);
}
if let Err(e) = send_command(launch_cmd, &flags.session) {
if !flags.json {
eprintln!("\x1b[33m⚠\x1b[0m Could not launch headed browser: {}", e);
eprintln!("\x1b[33m⚠\x1b[0m Could not launch browser: {}", e);
}
}
}
+2
View File
@@ -1189,6 +1189,7 @@ Snapshot Options:
Options:
--session <name> Isolated session (or AGENT_BROWSER_SESSION env)
--profile <path> Persistent browser profile (or AGENT_BROWSER_PROFILE env)
--headers <json> HTTP headers scoped to URL's origin (for auth)
--executable-path <path> Custom browser executable (or AGENT_BROWSER_EXECUTABLE_PATH)
--extension <path> Load browser extensions (repeatable).
@@ -1207,6 +1208,7 @@ Examples:
agent-browser get text @e1
agent-browser screenshot --full
agent-browser --cdp 9222 snapshot # Connect via CDP port
agent-browser --profile ~/.myapp open example.com # Persistent profile
"#
);
}