diff --git a/doc/example.md b/doc/example.md
index 5a1816a7e0d81756c8012f1b6fa7d4c8a4a0f342..01d1d40fe64927998f5ee5948163badd031c2711 100644
--- a/doc/example.md
+++ b/doc/example.md
@@ -34,6 +34,8 @@ gcli config
 gcli config where
 # save config to use gdev network for next commands
 gcli --network gdev config save
+# save config to use Alice predefined secret
+gcli -S predefined -s Alice config save
 ```
 
 ## Commands
diff --git a/src/commands/account.rs b/src/commands/account.rs
index eab3ceb3d8d8cc0fece69cf4c2f88d2f01ad4d72..04d058ef4e43b40a277f0c9556db1db0e8bda28a 100644
--- a/src/commands/account.rs
+++ b/src/commands/account.rs
@@ -31,10 +31,7 @@ pub async fn handle_command(data: Data, command: Subcommand) -> anyhow::Result<(
 	let mut data = data.build_client().await?;
 	match command {
 		Subcommand::Balance => {
-			data = data
-				.build_address()
-				.fetch_system_properties()
-				.await?;
+			data = data.fetch_system_properties().await?;
 			commands::account::get_balance(data).await?
 		}
 		Subcommand::Transfer {
@@ -42,22 +39,11 @@ pub async fn handle_command(data: Data, command: Subcommand) -> anyhow::Result<(
 			dest,
 			keep_alive,
 		} => {
-			data = data.build_client().await?;
-			commands::transfer::transfer(
-				&data,
-				amount,
-				dest,
-				keep_alive,
-			)
-			.await?;
+			data = data;
+			commands::transfer::transfer(&data, amount, dest, keep_alive).await?;
 		}
 		Subcommand::TransferMultiple { amount, dests } => {
-			data = data.build_client().await?;
-			commands::transfer::transfer_multiple(&data,
-				amount,
-				dests,
-			)
-			.await?;
+			commands::transfer::transfer_multiple(&data, amount, dests).await?;
 		}
 	};
 
diff --git a/src/commands/blockchain.rs b/src/commands/blockchain.rs
index 85d53d55b49a7a01538f1a07b3fc29286c31039f..ec869d2e7606b750147a658ea60bd785e4134fcf 100644
--- a/src/commands/blockchain.rs
+++ b/src/commands/blockchain.rs
@@ -27,9 +27,7 @@ pub async fn handle_command(data: Data, command: Subcommand) -> anyhow::Result<(
 		Subcommand::Repart {
 			target,
 			actual_repart,
-		} => {
-			commands::net_test::repart(&data, target, actual_repart).await?
-		}
+		} => commands::net_test::repart(&data, target, actual_repart).await?,
 		Subcommand::SpamRoll { actual_repart } => {
 			commands::net_test::spam_roll(&data, actual_repart).await?
 		}
diff --git a/src/commands/identity.rs b/src/commands/identity.rs
index 81a08baf28f7242f8c869535173e53f537cc32f9..3d676d663c6169f48a71d325c70a372b1bd2df4c 100644
--- a/src/commands/identity.rs
+++ b/src/commands/identity.rs
@@ -55,22 +55,19 @@ pub async fn handle_command(data: Data, command: Subcommand) -> anyhow::Result<(
 			.await?
 		}
 		Subcommand::Create { target } => {
-			data = data.build_keypair();
+			data = data;
 			commands::identity::create_identity(data.keypair(), data.client(), target).await?;
 		}
 		Subcommand::Confirm { name } => {
-			data = data.build_keypair();
+			data = data;
 			commands::identity::confirm_identity(data.keypair(), data.client(), name).await?;
 		}
 		Subcommand::Revoke => {
-			data = data.build_keypair().fetch_idty_index().await?;
+			data = data.fetch_idty_index().await?;
 			commands::identity::revoke_identity(data).await?;
 		}
 		Subcommand::GenRevocDoc => {
-			data = data
-				.build_keypair()
-				.fetch_idty_index()
-				.await?;
+			data = data.fetch_idty_index().await?;
 			commands::revocation::print_revoc_sig(&data)
 		}
 	};
@@ -136,7 +133,10 @@ pub async fn get_identity(
 	if let (Some(indexer), Some(account_id), None) = (&indexer, &account_id, &username) {
 		username = indexer.username_by_pubkey(&account_id.to_string()).await?;
 	}
-	println!("Username:    {}", username.unwrap_or("<no indexer>".to_string()));
+	println!(
+		"Username:    {}",
+		username.unwrap_or("<no indexer>".to_string())
+	);
 
 	Ok(())
 }
diff --git a/src/commands/net_test.rs b/src/commands/net_test.rs
index f216b6fb5fc513a67dce0c5b179758744155a3a4..ca8648021516a72b342639148c0d2964c685f507 100644
--- a/src/commands/net_test.rs
+++ b/src/commands/net_test.rs
@@ -3,14 +3,11 @@ use crate::*;
 use sp_core::DeriveJunction;
 use subxt::ext::sp_runtime::MultiAddress;
 
-pub async fn repart(
-	data: &Data,
-	target: u32,
-	actual_repart: Option<u32>,
-) -> anyhow::Result<()> {
+pub async fn repart(data: &Data, target: u32, actual_repart: Option<u32>) -> anyhow::Result<()> {
 	let mut pairs = Vec::new();
 	for i in actual_repart.unwrap_or_default()..target {
-		let pair_i = data.keypair()
+		let pair_i = data
+			.keypair()
 			.derive(std::iter::once(DeriveJunction::hard::<u32>(i)), None)
 			.map_err(|_| anyhow!("Fail to derive //{}", i))?
 			.0;
@@ -28,7 +25,8 @@ pub async fn repart(
 			.await?;
 		signer.increment_nonce();*/
 
-		if let Some(pair_i_account) = data.client()
+		if let Some(pair_i_account) = data
+			.client()
 			.storage()
 			.fetch(
 				&runtime::storage().system().account(&pair_i.public().into()),
@@ -48,7 +46,8 @@ pub async fn spam_roll(data: &Data, actual_repart: usize) -> anyhow::Result<()>
 	let mut nonce = 0;
 	let mut pairs = Vec::<(PairSigner<Runtime, Pair>, AccountId)>::with_capacity(actual_repart);
 	for i in 0..actual_repart {
-		let pair_i = data.keypair()
+		let pair_i = data
+			.keypair()
 			.derive(std::iter::once(DeriveJunction::hard::<u32>(i as u32)), None)
 			.map_err(|_| anyhow!("Fail to derive //{}", i))?
 			.0;
diff --git a/src/commands/smith.rs b/src/commands/smith.rs
index 01525bbe3c176668c5b9d7bd536f16adf92db2a8..96092c4d60fdbffdaefc9eab6a7cd859cd07d11c 100644
--- a/src/commands/smith.rs
+++ b/src/commands/smith.rs
@@ -4,7 +4,8 @@ use std::ops::Deref;
 
 type SessionKeys = [u8; 128];
 #[cfg(feature = "gdev")]
-type SmithMembershipMetaData = runtime::runtime_types::common_runtime::entities::SmithMembershipMetaData::<SessionKeys>;
+type SmithMembershipMetaData =
+	runtime::runtime_types::common_runtime::entities::SmithMembershipMetaData<SessionKeys>;
 
 /// define smith subcommands
 #[derive(Clone, Default, Debug, clap::Parser)]
@@ -40,7 +41,6 @@ pub async fn handle_command(data: Data, command: Subcommand) -> anyhow::Result<(
 	let mut data = data.build_client().await?;
 	match command {
 		Subcommand::Request { endpoint } => {
-			data = data.build_keypair();
 			dbg!(request_smith_membership(&data, endpoint).await)?;
 		}
 		Subcommand::GoOnline => {
@@ -50,14 +50,14 @@ pub async fn handle_command(data: Data, command: Subcommand) -> anyhow::Result<(
 			go_offline(&data).await?;
 		}
 		Subcommand::Cert { to } => {
-			data = data.build_keypair().fetch_idty_index().await?;
+			data = data.fetch_idty_index().await?;
 			cert(&data, to).await?
 		}
 		Subcommand::UpdateKeys => {
 			update_session_keys(&data).await?;
 		}
 		Subcommand::SudoSetKey { new_key } => {
-			data = data.build_keypair().build_client().await?;
+			data = data.build_client().await?;
 			commands::sudo::set_key(data.keypair(), data.client(), new_key).await?;
 		}
 		Subcommand::ShowExpire { blocks, sessions } => {
@@ -88,12 +88,11 @@ pub async fn rotate_keys(client: &Client) -> Result<SessionKeys, anyhow::Error>
 /// request smith membership
 pub async fn request_smith_membership(data: &Data, endpoint: String) -> Result<(), anyhow::Error> {
 	let session_keys = rotate_keys(data.client()).await?;
-	let metadata =
-		SmithMembershipMetaData {
-			session_keys,
-			owner_key: data.address(),
-			p2p_endpoint: endpoint,
-		};
+	let metadata = SmithMembershipMetaData {
+		session_keys,
+		owner_key: data.address(),
+		p2p_endpoint: endpoint,
+	};
 	let progress = data
 		.client()
 		.tx()
diff --git a/src/commands/ud.rs b/src/commands/ud.rs
index 6eccdd37d92d0da43953c5af4246d74e2208f589..7bc6d9faf5e1a60d00fb9512cfd676eecab44ef6 100644
--- a/src/commands/ud.rs
+++ b/src/commands/ud.rs
@@ -15,7 +15,7 @@ pub async fn handle_command(data: Data, command: Subcommand) -> anyhow::Result<(
 	// match subcommand
 	match command {
 		Subcommand::Claim => {
-			data = data.build_keypair();
+			data = data;
 			claim_ud(data).await?;
 		}
 	};
diff --git a/src/conf.rs b/src/conf.rs
index 7b5afba8ca5ce5cf2085d2ffb21cb4fb0fb3fb47..da063b141c38e52b46b7a56246a174b3d5c92a07 100644
--- a/src/conf.rs
+++ b/src/conf.rs
@@ -3,6 +3,7 @@ use serde::{Deserialize, Serialize};
 
 const APP_NAME: &str = "gcli";
 
+/// defines structure of config file
 #[derive(Serialize, Deserialize, Debug)]
 pub struct Config {
 	// duniter endpoint
@@ -11,6 +12,8 @@ pub struct Config {
 	pub indexer_endpoint: String,
 	// user address
 	pub address: Option<AccountId>,
+	// user secret (substrate format)
+	pub secret: Option<String>,
 }
 
 impl std::default::Default for Config {
@@ -19,6 +22,7 @@ impl std::default::Default for Config {
 			duniter_endpoint: String::from(data::LOCAL_DUNITER_ENDPOINT),
 			indexer_endpoint: String::from(data::LOCAL_INDEXER_ENDPOINT),
 			address: None,
+			secret: None,
 		}
 	}
 }
@@ -28,11 +32,16 @@ pub fn load_conf() -> Config {
 	match confy::load(APP_NAME, None) {
 		Ok(cfg) => cfg,
 		Err(e) => {
-			log::warn!("met error while loading config file");
-			log::error!("{}", e);
-			log::info!("removing the old conf file and creating a new one");
+			log::warn!(
+				"met error while loading config file {}",
+				confy::get_configuration_file_path(APP_NAME, None)
+					.unwrap()
+					.display()
+			);
+			log::error!("{:?}", e);
+			log::info!("using default config instead");
+			log::info!("call `config save` to overwrite");
 			let cfg = Config::default();
-			confy::store(APP_NAME, None, &cfg).expect("unable to write default config");
 			cfg
 		}
 	}
diff --git a/src/data.rs b/src/data.rs
index be67bec4881a9df1232adc10fa522c8f8df9d7cf..16901cdca612cfce799197a8cd64d09ff1e1da87 100644
--- a/src/data.rs
+++ b/src/data.rs
@@ -1,7 +1,11 @@
+use std::str::FromStr;
+
 use crate::*;
 use indexer::Indexer;
 
 // consts
+pub const SUBSTRATE_MNEMONIC: &str =
+	"bottom drive obey lake curtain smoke basket hold race lonely fit walk";
 pub const LOCAL_DUNITER_ENDPOINT: &str = "ws://localhost:9944";
 pub const LOCAL_INDEXER_ENDPOINT: &str = "http://localhost:8080/v1/graphql";
 
@@ -67,6 +71,7 @@ impl Data {
 			..Default::default()
 		}
 		.overwrite_from_args()
+		.build_from_config()
 	}
 	// --- getters ---
 	// the "unwrap" should not fail if data is well prepared
@@ -80,7 +85,10 @@ impl Data {
 		self.cfg.address.clone().expect("an address is needed")
 	}
 	pub fn keypair(&self) -> Pair {
-		self.keypair.clone().expect("a keypair is needed")
+		match self.keypair.clone() {
+			Some(keypair) => keypair,
+			None => prompt_secret(self.args.secret_format),
+		}
 	}
 	pub fn idty_index(&self) -> u32 {
 		self.idty_index.expect("must fetch idty index first")
@@ -138,45 +146,39 @@ impl Data {
 		if let Some(indexer_endpoint) = self.args.indexer.clone() {
 			self.cfg.indexer_endpoint = indexer_endpoint
 		}
-		// secret
-		if self.args.secret.is_some() {
-			self = self.build_keypair();
+		// predefined secret
+		if self.args.secret_format == SecretFormat::Predefined {
+			match self.args.secret.clone() {
+				None => {}
+				Some(derivation) => {
+					self.cfg.secret = Some(format!("{SUBSTRATE_MNEMONIC}//{derivation}"));
+				}
+			};
+		} else if let Some(secret) = self.args.secret.clone() {
+			// other secret type
+			self.cfg.secret = Some(secret);
 		}
 		// address
-		if self.args.address.is_some() {
-			self = self.build_address();
-		}
-		self
-	}
-	/// ask user to input an address if needed
-	pub fn build_address(mut self) -> Self {
-		if self.cfg.address.is_none() {
-			self.cfg.address = Some(
-				get_keys(
-					self.args.secret_format,
-					&self.args.address,
-					&self.args.secret,
-					NeededKeys::Public,
-				)
-				.expect("needed")
-				.0
-				.expect("needed"),
-			);
+		if let Some(address) = self.args.address.clone() {
+			self.cfg.address = Some(AccountId::from_str(&address).expect("invalid address"));
 		}
 		self
 	}
-	/// ask user to input a keypair if needed
-	pub fn build_keypair(mut self) -> Self {
-		if self.keypair.is_none() {
-			let (address, keypair) = get_keys(
-				self.args.secret_format,
-				&self.args.address,
-				&self.args.secret,
-				NeededKeys::Secret,
-			)
-			.expect("needed");
-			self.cfg.address = address;
-			self.keypair = keypair;
+	/// build from config
+	pub fn build_from_config(mut self) -> Self {
+		// if a secret is defined, build keypair
+		if let Some(secret) = self.cfg.secret.clone() {
+			let (address, keypair) =
+				addr_and_pair_from_secret(SecretFormat::Predefined, &secret).unwrap();
+			// if an address is already defined and differs from secret, warns user
+			if let Some(address_) = self.cfg.address {
+				if address_ != address {
+					println!("overwriting address ({address_}) from secret ({address})");
+				}
+			}
+			self.cfg.address = Some(address);
+			self.cfg.secret = Some(secret);
+			self.keypair = Some(keypair);
 		}
 		self
 	}
@@ -187,7 +189,7 @@ impl Data {
 			GcliError::Duniter(format!(
 				"could not establish connection with the server {}, due to error {}",
 				duniter_endpoint,
-				dbg!(e)
+				dbg!(e) // needed to get more details TODO fixme
 			))
 		})?);
 		self.genesis_hash = commands::blockchain::fetch_genesis_hash(&self).await?;
diff --git a/src/keys.rs b/src/keys.rs
index 8df0ebae6656bd7ac0d58b29c7eb91cd739509df..5ac176d21c621522c78ed385b0651c2b71b945d0 100644
--- a/src/keys.rs
+++ b/src/keys.rs
@@ -1,16 +1,14 @@
 use crate::*;
 
 use clap::builder::OsStr;
-use sp_core::crypto::Ss58Codec;
 use std::str::FromStr;
 
-#[allow(dead_code)]
-#[derive(Clone, Copy, Debug, Eq, PartialEq)]
-pub enum NeededKeys {
-	None,
-	Public,
-	Secret,
-}
+// #[derive(Clone, Copy, Debug, Eq, PartialEq)]
+// pub enum NeededKeys {
+// 	None,
+// 	Public,
+// 	Secret,
+// }
 
 #[derive(Clone, Copy, Debug, Eq, PartialEq, Default)]
 pub enum SecretFormat {
@@ -19,6 +17,8 @@ pub enum SecretFormat {
 	/// Substrate secret key or BIP39 mnemonic (optionally followed by derivation path)
 	#[default]
 	Substrate,
+	/// Predefined (Alice, Bob, ...)
+	Predefined,
 }
 
 impl FromStr for SecretFormat {
@@ -28,6 +28,7 @@ impl FromStr for SecretFormat {
 		match s {
 			"seed" => Ok(SecretFormat::Seed),
 			"substrate" => Ok(SecretFormat::Substrate),
+			"predefined" => Ok(SecretFormat::Predefined),
 			_ => Err(std::io::Error::from(std::io::ErrorKind::InvalidInput)),
 		}
 	}
@@ -38,6 +39,7 @@ impl From<SecretFormat> for &'static str {
 		match val {
 			SecretFormat::Seed => "seed",
 			SecretFormat::Substrate => "substrate",
+			SecretFormat::Predefined => "predefined",
 		}
 	}
 }
@@ -48,6 +50,7 @@ impl From<SecretFormat> for OsStr {
 	}
 }
 
+/// get keypair from given string secret
 pub fn pair_from_str(secret_format: SecretFormat, secret: &str) -> anyhow::Result<Pair> {
 	match secret_format {
 		SecretFormat::Seed => {
@@ -56,12 +59,24 @@ pub fn pair_from_str(secret_format: SecretFormat, secret: &str) -> anyhow::Resul
 			let pair = Pair::from_seed(&seed);
 			Ok(pair)
 		}
-		SecretFormat::Substrate => {
+		// "predefined" replaces secret before
+		SecretFormat::Substrate | SecretFormat::Predefined => {
 			Pair::from_string(secret, None).map_err(|_| anyhow!("Invalid secret"))
 		}
 	}
 }
 
+/// get keypair and address from given secret string
+pub fn addr_and_pair_from_secret(
+	secret_format: SecretFormat,
+	secret: &str,
+) -> anyhow::Result<(AccountId, Pair)> {
+	let pair = pair_from_str(secret_format, secret)?;
+	let address = pair.public().into();
+	Ok((address, pair))
+}
+
+/// ask user to input a secret
 pub fn prompt_secret(secret_format: SecretFormat) -> Pair {
 	loop {
 		match pair_from_str(
@@ -74,52 +89,53 @@ pub fn prompt_secret(secret_format: SecretFormat) -> Pair {
 	}
 }
 
-pub fn get_keys(
-	secret_format: SecretFormat,
-	address: &Option<String>,
-	secret: &Option<String>,
-	needed_keys: NeededKeys,
-) -> anyhow::Result<(Option<AccountId>, Option<Pair>)> {
-	// Get from args
-	let mut account_id = match (address, secret) {
-		(Some(address), Some(secret)) => {
-			let pair = pair_from_str(secret_format, secret)?;
-			let address = AccountId::from_string(address)
-				.map_err(|_| anyhow!("Invalid address {}", address))?;
-			assert_eq!(
-				address,
-				pair.public().into(),
-				"Secret and address do not match."
-			);
-			return Ok((Some(pair.public().into()), Some(pair)));
-		}
-		(None, Some(secret)) => {
-			let pair = pair_from_str(secret_format, secret)?;
-			return Ok((Some(pair.public().into()), Some(pair)));
-		}
-		(Some(address), None) => {
-			Some(AccountId::from_str(address).map_err(|_| anyhow!("Invalid address {}", address))?)
-		}
-		(None, None) => None,
-	};
+// /// get keys with interactive prompt if needed
+// pub fn get_keys(
+// 	secret_format: SecretFormat,
+// 	accout_id: Option<AccountId>,
+// 	secret: &Option<String>,
+// 	needed_keys: NeededKeys,
+// ) -> anyhow::Result<(Option<AccountId>, Option<Pair>)> {
+// 	// Get from args
+// 	let mut account_id = match (accout_id, secret) {
+// 		// both are defined, check that they match.
+// 		// if they do not match, use secret
+// 		(Some(accout_id), Some(secret)) => {
+// 			let pair = pair_from_str(secret_format, secret)?;
+// 			let secret_address = pair.public().into();
+// 			if accout_id != secret_address {
+// 				println!("Secret ({secret_address}) and address ({accout_id}) do not match, using secret");
+// 			}
+// 			return Ok((Some(secret_address), Some(pair)));
+// 		}
+// 		// only secret, build both
+// 		(None, Some(secret)) => {
+// 			let pair = pair_from_str(secret_format, secret)?;
+// 			return Ok((Some(pair.public().into()), Some(pair)));
+// 		}
+// 		// only address
+// 		(Some(accout_id), None) => Some(accout_id),
+// 		// none of them
+// 		(None, None) => None,
+// 	};
 
-	// Prompt
-	if needed_keys == NeededKeys::Secret
-		|| (account_id.is_none() && needed_keys == NeededKeys::Public)
-	{
-		loop {
-			let pair = prompt_secret(secret_format);
+// 	// Prompt
+// 	if needed_keys == NeededKeys::Secret
+// 		|| (account_id.is_none() && needed_keys == NeededKeys::Public)
+// 	{
+// 		loop {
+// 			let pair = prompt_secret(secret_format);
 
-			if let Some(account_id) = &account_id {
-				if account_id != &pair.public().into() {
-					println!("Secret and address do not match.");
-				}
-			} else {
-				account_id = Some(pair.public().into());
-				return Ok((account_id, Some(pair)));
-			}
-		}
-	}
+// 			if let Some(account_id) = &account_id {
+// 				if account_id != &pair.public().into() {
+// 					println!("Secret and address do not match.");
+// 				}
+// 			} else {
+// 				account_id = Some(pair.public().into());
+// 				return Ok((account_id, Some(pair)));
+// 			}
+// 		}
+// 	}
 
-	Ok((account_id, None))
-}
+// 	Ok((account_id, None))
+// }
diff --git a/src/main.rs b/src/main.rs
index 071115e16afcd884946a77aaa5189f00ecf469d5..3633553b7598cf71d4754d930f9e1d4c482e26fc 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -112,7 +112,9 @@ async fn main() -> Result<(), GcliError> {
 		Subcommand::Oneshot(subcommand) => {
 			commands::oneshot::handle_command(data, subcommand).await?
 		}
-		Subcommand::Blockchain(subcommand) => commands::blockchain::handle_command(data, subcommand).await?,
+		Subcommand::Blockchain(subcommand) => {
+			commands::blockchain::handle_command(data, subcommand).await?
+		}
 		Subcommand::Indexer(subcommand) => indexer::handle_command(data, subcommand).await?,
 		Subcommand::Config(subcommand) => conf::handle_command(data, subcommand)?,
 	}